2012-05-05 114 views
6

我有一個多對多的關係,用MySQL中的關聯表實現。我有一張兒童桌子和一張父母桌子。一個孩子可以有多個父母,並使用他們的ID保存在parent_child_link關聯表中。PHP更新MYSQL多對多關係

孩子們可以通過HTML表單進行更新,父母都在HTML多選。現在我需要更新數據庫中的記錄,但我的解決方案效率不高。下面是僞代碼我做什麼:

  1. 更新孩子的信息,其中child_id = X
  2. 刪除所有當前協會parent_child_link其中child_id = X
  3. 插入新的關聯

該解決方案很好,但是當父母沒有改變時,例如只有孩子的名字被改變了,然後有2個不必要的查詢被執行。我怎樣才能避免這些不必要的查詢?有沒有辦法檢查多選的父母是否沒有改變?

當然,我可以忽略所有這些麻煩,因爲它已經有效,但我真的很喜歡讓事情儘可能高效。

回答

0

嘗試通過在子表的定義中使用ON UPDATE CASCADEON DELETE CASCADE來解決它在數據庫中,而不是在應用程序層中。

稍微修改了例形成MySQL網站:

CREATE TABLE parent (id INT NOT NULL, 
        PRIMARY KEY (id) 
) ENGINE=INNODB; 

CREATE TABLE child (id INT, parent_id INT, 
        INDEX par_ind (parent_id), 
        FOREIGN KEY (parent_id) REFERENCES parent(id) 
         ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=INNODB; 

退房這裏的文檔:http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

編輯:爲了您的許多一對多的關係,你可以使用類似:

CREATE TABLE parent_child_link (
        parent_id INT NOT NULL, 
        child_id INT NOT NULL, 
        PRIMARY KEY(parent_id, child_id), 
        FOREIGN KEY (parent_id) REFERENCES parent(id) 
         ON DELETE CASCADE ON UPDATE CASCADE, 
        FOREIGN KEY (child_id) REFERENCES child(id) 
         ON DELETE CASCADE ON UPDATE CASCADE 
); 

希望這有助於。

+0

這是一對一; OP與數據透視表有多對多的關係。 – lafor

+0

你的權利,我的壞。 –

+1

我很想將它移到應用程序層之外,但我不明白你的解決方案和參考如何解決我的問題。據我設法分析它,刪除一個孩子或父母(以擺脫鏈接)將是有用的。 – EsTeGe

0

您的解決方案很好。
對於您的情況,您可以通過查詢來檢索父母,並在發生任何更改時檢查多選數據來「優化」流程。
然後,如果需要,您只執行兩個刪除和插入查詢。與此相對應的是,當你真的改變了父母,那麼將會有3個問題,而不是2個。
所以你應該問你是否要經常修改父母。在這種情況下,您應該堅持原來的解決方案,以避免額外的選擇查詢。
如果您認爲父母不會經常更新,那麼您可以使用上述解決方案。當您僅更新子級信息時,只執行一個查詢。當您還更新父母時,會執行3個查詢。
當您使用第二種解決方案時,可以優化刪除和插入查詢以僅執行所需的操作(僅刪除不再是其父母的父母,並僅插入新的父鏈接)。
PHP數組函數對此可能很有幫助。

0

如果你想保持你目前的做法,但只是優化,你可以用IF語句包裝查詢。

像:

if (isset ($parent_name_change)){ // run query }

7

我有同樣的問題,找到了我的解決方案,因爲我在看書。

當我準備好處理提交的條目時,首先執行查詢以獲取當前關聯並調用該數組$ original_list。提交的列表我將調用$ submitted_list。

$original_list = array(3,5,7); 
$submitted_list = array(1,2,3); 

然後我只需要弄清楚1)要刪除的項目(不再存在)和2)要添加的項目(新的關聯)。兩個列表中的項目都不會被觸及。

$delete_list = array_diff($original_list, $submitted_list); 
$insert_list = array_diff($submitted_list, $original_list); 

foreach($delete_list as $item) { 
    // delete $item from DB 
} 

foreach($insert_list as $item) { 
    // insert item in db 
} 

想知道別人是否覺得這是一個有效的解決方案。

+1

是的,這是我過去做過類似事情的方式。通常我會採用delte - > insert方法,但如果其他地方引用了孩子的ID,那麼這可能會成爲問題,例如,如果您將多個價格條目添加到產品中,並且價格ID是從購物車引用的。當價格在技術上沒有改變時,不能改變ID。 – jammypeach