从具有外部约束的多个表中删除

F21*_*F21 19 mysql sql foreign-keys sql-delete

我想从多个表中删除.这是我的表格的样子

    A_has_B ---- B ---- C_has_B
(many to many)        (many to many)
Run Code Online (Sandbox Code Playgroud)

我正在尝试删除A_has_B,B和C_has_B中的所有行,给定B中记录的ID.我使用带有innodb存储引擎的MySQL,其中为A_has_B定义了外键,而C_has_B引用了B中的ID.

我试图像这样执行删除:

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);
Run Code Online (Sandbox Code Playgroud)

问题是,当我执行查询时,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)
Run Code Online (Sandbox Code Playgroud)

我该怎么办呢?

Mar*_*rot 31

最简单的方法是从每个表中单独删除:

-- 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);
Run Code Online (Sandbox Code Playgroud)

MySQL还允许您在一个语句中从多个表中删除.但是没有办法控制删除的顺序.从手册:

如果您使用涉及具有外键约束的InnoDB表的多表DELETE语句,则MySQL优化器可能会按照与其父/子关系不同的顺序处理表.在这种情况下,语句失败并回滚.相反,您应该从单个表中删除并依赖InnoDB提供的ON DELETE功能来相应地修改其他表.

  • 在SQL中,它的`transactional`性质旨在允许多个语句完成*as-if*它们是单个语句.而不是实现一个不可能复杂的语言和一个不可能复杂的引擎/优化器.所以,如果重要的是"立刻"删除所有内容,请查看交易:) (2认同)

And*_*rey 9

实际上,在MySQL中,您可以关闭对外键约束的检查

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
--your SQL statements
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
Run Code Online (Sandbox Code Playgroud)

第一行上的语句强制MySQL服务器关闭外键检查,最后一行将其重新打开(非常重要).要记住两件事:

  • 关闭约束检查是相当危险的,并且不应该在生产数据库中完成......最安全的方法是使用单独的语句.
  • 始终重新打开约束检查


小智 5

您可以在外键上指定“删除级联”。当删除父行时,mysql引擎会删除相关子表中的记录