2011-07-30 67 views
16

我試圖從多個表中刪除。下面是我的表像從具有外部約束的多個表中刪除

A_has_B ---- B ---- C_has_B 
(many to many)  (many to many) 

我試圖刪除A_has_B,B和C_has_B所有行給定的記錄中,我使用MySQL與用於A_has_B定義的外鍵InnoDB存儲引擎B的ID和C_has_B引用的ID在B.

我想履行我刪除像這樣:

DELETE A_has_B.*, C_has_B.*, B.* 

FROM 
A 

join 
B 
on (B.B_id = A.B_id) 

join 
C 
on (C.B_id = B.B_id) 

where B.B_id IN(1,2, 4); 

的問題是,當我執行查詢,MySQL的抱怨:

Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails (`db`.`C`, CONSTRAINT `fk_C` FOREIGN KEY (`B_id`) REFERENCES `B` (`B_id`) ON DELETE NO ACTION ON UPDATE NO) 

我該如何解決這個問題?

回答

25

最簡單的方法是從每個單獨的表中刪除:

-- Remove all connections from A which reference 
-- the B-rows you want to remove 
DELETE FROM A_has_B 
WHERE B_id IN (1,2,4); 

-- Remove all connections from C which reference 
-- the B-rows you want to remove 
DELETE FROM C_has_B 
WHERE B_id IN (1,2,4); 

-- Finally remove the B-rows 
DELETE FROM B 
WHERE B_id IN (1,2,4); 

MySQL還允許您從多個表在一個聲明中刪除。但是沒有辦法控制刪除的順序。從manual

如果使用多表DELETE涉及針對有外鍵約束InnoDB表的語句,MySQL優化器可以處理在從他們的父/子關係不同的順序表。在這種情況下,語句失敗並回滾。相反,您應該從單個表中刪除,並依靠InnoDB提供的ON DELETE功能來引起其他表的相應修改。

+0

感謝您的回答:)用一條語句刪除絕對不可能?我會想,也許我可以強制MySQL在從B刪除前從交叉表中刪除。 – F21

+2

在SQL中,它的'transactional'性質是爲了允許多個語句完成* as-if *它們是單個語句。而不是實現一個不可能的複雜語言和一個不可能的複雜引擎/優化器。所以,如果一切都被「一次」刪除很重要,那麼看看交易:) – MatBailie

0

在單獨的語句中執行刪除操作,它將起作用。

8

其實,在MySQL中,你可以關閉檢查外鍵約束

SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; 
--your SQL statements 
SET [email protected]_FOREIGN_KEY_CHECKS; 

在第一行的語句強制MySQL服務器關閉外鍵檢查和最後一行把它們回在(非常重要)。有兩件事情要記住:

  • 這是相當危險的,關閉檢查約束,是不是應該在做,比如說,一個生產DB ......最安全的方法是使用單獨的語句。
  • 務必將約束檢查回到
3

可以指定外鍵「刪除級聯」。 當你刪除父行時,mysql引擎會刪除相關子表中的記錄