使用Join和Foreign Key约束删除SQL

问题描述 投票:1回答:2

使用10.0.31-MariaDB-1~jessie

我有两个表:provider_contactprovider_contact_x_role,其中contact_id表中的provider_contact_x_role列在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 <> '[email protected]';

结果是以下错误:

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)知道这两个查询之间有什么区别(为什么第一个成功而第二个失败)?

sql join foreign-keys constraints delete-row
2个回答
1
投票

从MySQL文档中提取:

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

如果你使用EXPLAIN,你会发现它更喜欢主表首先过滤(和删除),因为它需要它来进行JOIN。

如果你使用INNER JOIN,你可以尝试STRAIGHT_JOIN,它与INNER JOIN相同,只是左表总是在右表之前读取,并按照你想要实现的删除顺序放置表。

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


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 <> '[email protected]';
© www.soinside.com 2019 - 2024. All rights reserved.