具有联接和外键约束的SQL删除

时间:2018-08-07 08:12:08

标签: sql join foreign-keys constraints delete-row

使用10.0.31-MariaDB-1~jessie

我有两个表:provider_contactprovider_contact_x_role,其中contact_id表中的provider_contact_x_role列具有对{{1}的id列的外键引用}表。

当我运行以下查询时,结果为成功:

provider_contact

当我运行下一个查询时:

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`)) 条件。

问题:

1)SQL中是否有任何东西可以确保在执行这些查询时,首先删除WHERE中的行?

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

2 个答案:

答案 0 :(得分:1)

摘自MySQL文档:

  

如果您使用涉及InnoDB表的多表DELETE语句   对于有外键约束的情况,MySQL优化器可能   处理表的顺序不同于它们的顺序   父母/子女关系。在这种情况下,该语句将失败并滚动   背部。相反,您应该从单个表中删除并依靠   InnoDB提供的ON DELETE功能导致其他表   进行相应的修改。

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

如果您使用INNER JOIN,则可以尝试与STRAIGHT_JOIN相同的INNER JOIN,不同之处在于:总是先读取左表,然后再将右表放在右表中。您想要实现的删除顺序。

作为级联的替代,您可以使用SET FOREIGN_KEY_CHECKS=0;禁用delete语句中的外键。

答案 1 :(得分:0)

您是否可以尝试先删除 provider_contact 表中的记录,而不要删除 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';