【问题标题】:SQL: Cannot delete or update parent row: a foreign key constraint failsSQL:无法删除或更新父行:外键约束失败
【发布时间】:2015-05-27 14:19:46
【问题描述】:

每当我尝试像这样从“调查”表中删除调查时:

DELETE FROM surveys WHERE survey_id = 77

它提示我如下所述的错误:

#1451 - 无法删除或更新父行:外键约束失败('user_surveys_archive', CONSTRAINT 'user_surveys_archive_ibfk_6' 外键('user_access_level_id') 参考 'user_surveys' ('user_access_level_id') ON DELETE NO ACTION )

第一件事:我没有任何名称为“user_surveys_archive_ibfk_6”的此类表

第二件事:其他表中没有本次调查的记录。

知道如何删除这条修复此问题的记录吗?

编辑

这是我在导出表格调查的表格约束时发现的行

ALTER TABLE `surveys`
ADD CONSTRAINT `surveys_ibfk_1` FOREIGN KEY (`survey_type_id`) REFERENCES `survey_types` (`survey_type_id`) ON DELETE CASCADE ON UPDATE NO ACTION;`

【问题讨论】:

  • user_surveys_archive_ibfk_6 是外键约束的名称,通常可以是您想要的任何东西 - 毕竟它只是一个名称。它看起来像一个自动生成的,所以它很可能在user_surveys_archive 表中。
  • 但是调查表中没有标题为“user_access_level_id”的列。关于如何调试它的任何想法?
  • 也许您在关闭 foreign_key_checks 的情况下执行了一些 alter 查询,从而破坏了 FK 系统。一旦重新启用检查,mysql 将不会扫描数据库以验证所有 FK 是否正常工作,因此在您尝试使用/引用现在不存在的字段/表的查询之前您不会注意到。
  • 它会隐藏错误,因为您已禁用 FK 检查。它不会解决问题...
  • surveys 上的外键不是问题所在。您需要查看 user_surveys 表上的外键。正如我在回答中解释的那样,我们预计这将是 FOREIGN KEY (survey_id) REFERENCES surveys(survey_id) ON DELETE CASCADE

标签: mysql sql


【解决方案1】:

您需要先删除或更新表 user_surveys_archive 中的一些行。

这些行与 user_surveys 表中的行相关。

很可能,在表 user_surveys 上定义了一个外键约束,它引用了您尝试删除的 surveys 中的行。

(您需要检查外键定义,最快的方法是

SHOW CREATE TABLE user_surveys 

然后寻找REFERENCES surveys。 (很可能,它有一个名为 survey_id 的列,但我们只是在猜测,没有查看外键约束的定义。)

要查找 user_surveys_archive 中阻止 DELETE 发生的行...

SELECT a.*
  FROM user_surveys_archvive a
  JOIN user_surveys u
    ON u.user_access_level_id = a.user_access_level_id  
  JOIN surveys s
    ON s.survey_id = u.survey_id    -- change this to whatever the FK is
 WHERE s.survey_id = 77

很可能从user_surveyssurveys 的外键约束是用ON DELETE CASCADE 定义的。从surveys 中删除行的尝试标识了user_surveys 中应自动删除的行。

user_surveys 中自动删除行的尝试违反了user_surveys_archive 中定义的外键约束。而那个外键没有ON DELETE CASCADE定义。

(另一种可能性是定义的触发器正在执行一些 DML 操作,但这很奇怪。)


确定行后,您需要决定进行哪些更改以允许您从 surveys 中删除行。

您可以删除行或更新它们。

要从user_surveys_archive 中删除行,请修改上面的查询并将SELECT 替换为DELETE。如果user_surveys_archive 中的user_access_level_id 列允许NULL 值,您可以进行更新。

SELECT a.* FROM 替换为 UPDATE,并在 WHERE 子句上方的一行添加 SET a.user_access_level_id = NULL...

UPDATE user_surveys_archvive a
  JOIN user_surveys u
    ON u.user_access_level_id = a.user_access_level_id  
  JOIN surveys s
    ON s.survey_id = u.survey_id    -- change this to whatever the FK is
   SET a.user_access_level_id = NULL
 WHERE s.survey_id = 77

(外键列的名称是user_access_level_id,这对我来说似乎很奇怪。但它只是一个列名,它可以被命名为任何东西......对我来说似乎很奇怪,因为我们遵循的约定和模式命名外键列。)

【讨论】:

  • 你能看看我刚刚做的编辑吗?我猜你已经很接近帮助我解决这个问题了。
  • surveys 表上定义的外键约束不是问题。您需要查看的是 user_surveys 表上的外键约束。我们期待看到的是 (survey_id) REFERENCES surveys(survey_id) ON DELETE CASCADE。 (我们并不关心约束的名称是什么。)
  • spencer7593 首先 +1 将所有内容写出来。此外,如果这些是一些有用的查询,应该可以帮助您找出问题,但是如果我们没有看到表/字段和适当的 FK 约束,就会有很多假设。您可能需要稍微调整它们或进行一些调整,但他的回答应该可以帮助您解决问题。
  • @JKirkbride:是的,有很多 的假设正在进行,我犹豫要不要写一个示例查询,因为我只是在猜测,没有看到实际的表定义。我的回答忽略了提及其他一些选项...可以修改外键约束以包含ON DELETE CASCADE,或者可以完全删除它。但我认为在我们提供更改架构的建议之前,OP 对正在发生的事情有一个很好的了解是重要的
【解决方案2】:

您应该允许外键为NULL,然后选择ON DELETE SET NULL

我个人建议同时使用“ON UPDATE CASCADE”和“ON DELETE SET NULL”来避免不必要的麻烦,但是您的设置可能需要不同的方法。

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    必须在可能名为 user_surveys_archive 的表中引用 77 的 survey_id。错误是说外键约束的名称是user_surveys_archive_ibfk_6。如果您需要删除survey_id = 77,则必须删除任何子记录或将其作为外键引用的其他记录。

    编辑 发布我的答案后,我看到了上面的 cmets。 atif user_surveys_archive 表中的外键名称可能不同,但仍等于您尝试删除和/或引用 survey_id 的值 77。如果不是这种情况,那么数据库中还有其他一些问题。您可以尝试查看 FK 的代码,了解它是如何制作的以及它引用了哪些字段,或者运行查询以查看 user_surveys_archive 中是否有任何记录,其中 user_access_level_id 为 = 77。

    Edit 2 spencer7593 的回答列出了如何运行我回答中提到的一些查询。

    【讨论】:

    • 如果我关闭这两个表的外键检查会怎样:SET FOREIGN_KEY_CHECKS=0;
    • 如上所述,这并不能解决更大的问题,只会掩盖它,并可能对数据的完整性产生负面影响。
    猜你喜欢
    • 2017-06-11
    • 1970-01-01
    • 2022-01-17
    • 2019-05-25
    • 2014-11-11
    • 2018-05-12
    • 2017-09-15
    • 1970-01-01
    相关资源
    最近更新 更多