SQL 使用连接和外键约束删除

SQL Delete with Join and Foreign Key constraint

使用 10.0.31-MariaDB-1~jessie.

我有两个 table:provider_contactprovider_contact_x_role 其中 provider_contact_x_role 中的 contact_id 列 table 有一个外键引用idprovider_contact table。

当我运行下面的查询结果是成功的:

DELETE cr, c
FROM provider_contact_x_role AS cr
INNER JOIN provider_contact AS c
ON cr.contact_id = c.id
WHERE c.is_test_contact = 0;

当我运行下一个查询时:

DELETE cr, c
FROM provider_contact_x_role AS cr
INNER JOIN provider_contact AS c
ON cr.contact_id = c.id
WHERE c.email_address <> 'suren@test.com';

结果是以下错误:

Cannot delete or update a parent row: a foreign key constraint fails 
(`ins_db`.`provider_contact_x_role`, CONSTRAINT 
`FK_contact_id--provider_contact.id` FOREIGN KEY (`contact_id`) 
REFERENCES `provider_contact` (`id`))

请注意,这两个查询之间的唯一区别是 WHERE 条件。

问题:

1) SQL 中是否有任何内容可确保在执行这些查询时首先删除 provider_contact_x_role 中的行?

2) 知道这两个查询之间有什么不同吗(为什么第一个成功而第二个失败)?

您能否尝试先删除 provider_contact table 中的记录,而不是 provider_contact_x_role 因为它从 contact_id 外键强制引用完整性。

DELETE c, cr
FROM provider_contact AS c
INNER JOIN provider_contact_x_role AS cr
ON c.id = cr.contact_id
WHERE c.email_address <> 'suren@test.com';

摘自 MySQL 文档:

If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly.

如果您使用 EXPLAIN,您会发现它更喜欢先按主 table 过滤(和删除),因为它需要它来执行 JOIN。

如果您使用 INNER JOIN,您可以尝试 STRAIGHT_JOIN,它与 INNER JOIN 相同,只是左边的 table 总是先于右边的 table 并把 table 放在你想要达到的删除顺序中。

除了级联之外,您可以使用 SET FOREIGN_KEY_CHECKS=0;.

在删除语句中禁用外键