假外键约束失败


110

我收到此错误消息:

第40行的错误1217(23000):无法删除或更新父行:外键约束失败

...当我尝试放一张桌子时:

DROP TABLE IF EXISTS `area`;

...定义如下:

CREATE TABLE `area` (
  `area_id` char(3) COLLATE utf8_spanish_ci NOT NULL,
  `nombre_area` varchar(30) COLLATE utf8_spanish_ci NOT NULL,
  `descripcion_area` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`area_id`),
  UNIQUE KEY `nombre_area_UNIQUE` (`nombre_area`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

有趣的是,我已经删除了模式中具有针对其的外键的所有其他表area。实际上,除area表外,数据库为空。

如果数据库中没有其他对象,它怎么可能有子行?据我所知,InnoDB不允许在其他模式上使用外键,对吗?

(我什至可以运行RENAME TABLE area TO something_else命令:-?)


该表是否可能是另一个模式中“引用完整性”关系的一部分?
Raj More

我还有该应用程序的其他副本,因此始终可以。但是,我使用的语法基本上是CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id),即表引用上没有模式名称:-?
阿尔瓦罗·冈萨雷斯

Answers:


101

两种可能性:

  1. 在另一个架构(mysql术语中的“数据库”)中有一个表,该表具有FK参考
  2. innodb内部数据字典与mysql字典不同步。

通过在删除失败后执行“ SHOW ENGINE INNODB STATUS”,可以查看它是哪个表(无论如何是其中之一)。

如果是后一种情况,我将转储并还原整个服务器(如果可以)。

MySQL 5.1及更高版本将为您提供错误消息中带有FK的表的名称。


1
我不再能重现该问题。字典不同步是可能的原因。我将每天进行测试,看看有什么SHOW ENGINE INNODB STATUS报告。
阿尔瓦罗·冈萨雷斯

3
感谢您的回答!我有一个多对多表仍在引用我们无法删除的表,因此我必须首先删除该表。
Christian Oudard 2011年

5
SHOW ENGINE INNODB STATUS在“最新外键错误”下列出了最后一个外键错误。有时间戳记。
bbrame 2014年

可能有一个表仍然具有主题表的参考键。就我而言,就是这样。
RT

节省了很多时间。将数据库
删除

121

随需应变,现在作为答案...

当使用MySQL Query Browser或phpMyAdmin时,似乎为每个查询打开了一个新连接(bugs.mysql.com/bug.php?id=8280),因此有必要在一个查询中写入所有drop语句,例如。

SET FOREIGN_KEY_CHECKS=0; 
DROP TABLE my_first_table_to_drop; 
DROP TABLE my_second_table_to_drop; 
SET FOREIGN_KEY_CHECKS=1; 

SET FOREIGN_KEY_CHECKS=1作为一个额外的安全措施?


2
对于使用phpMyAdmin创建转储的用户,有一个选项“禁用外键检查”将自动添加SET FOREIGN_KEY_CHECKS=0;到转储的开头。
迈克

好像phpMyAdmin实现了这个可爱的功能,现在我正在等待mysqlWorkbench做同样的事情!:)
Karlis Rode

@CodeMed仅供参考,我接受MarkR的回答是因为它提供了有意义的问题的解释-尽管我承认我无法验证它,因为在接下来的6年中我没有遇到过同样的问题,甚至没有一次。这个和较早的答案提供了一种解决方法(非常好),但是并不能真正解决问题本身,因为您只能接受我不得不选择的一个答案。
阿尔瓦罗冈萨雷斯

1
警告:这不是解决方案,而只是懒惰的解决方法。使用这种(与指向被删除表的一些其他表中的记录)后,您将体验晃来晃去的外键,其致命破坏的一致性(该ÇACID数据库)和应用程序将开始抛出异常,所有的地方。您已被警告。
bekce

尽管我确信bekce的警告应该得到理解和注意,但是这种解决方案确实对我有用,在这种情况下,我确信自己还会删除所有指向表的表,这些表指向的表具有麻烦的外键约束。
user1147171

47

禁用外键检查

SET FOREIGN_KEY_CHECKS=0

62
正确的命令似乎是SET FOREIGN_KEY_CHECKS=0,它确实可以修复错误消息。您对为什么需要这样做有任何想法吗?即使表消失了,外键也被缓存了吗?
阿尔瓦罗·冈萨雷斯

1
说实话,我不知道为什么会出现这种问题,但是请确保每次进行一些大的更改或更新时都禁用密钥检查。这件事发生在我身上好几次,使我几天都无法入睡。
Flakron Bytyqi,2010年

55
SET FOREIGN_KEY_CHECKS=1;完成后一定要确保!
pedro_sland 2010年

5
当使用MySQL Query Browser或phpMyAdmin时,似乎为每个查询打开了一个新连接(bugs.mysql.com/bug.php?id=8280),因此有必要在一个查询中写入所有drop语句,例如。SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; SET FOREIGN_KEY_CHECKS = 1可以作为一项额外的安全措施...
卡利斯·罗德

1
@ KarlisRode,Bravo对phpMyAdmin进行了评论。如果您将其作为答案,我将对其+1。
Sablefoste

28

这个博客

您可以暂时禁用外键检查:

SET FOREIGN_KEY_CHECKS=0;

完成混乱后,只需确保将它们还原:

SET FOREIGN_KEY_CHECKS=1;

不错的答案,因为我正在本地开发:)
Adelin

这是一个有效的解决方法(我可以确认它是可行的),但是链接的博客条目并未真正讨论此问题中的情况(一个表已经保存了一个空的数据库)。
阿尔瓦罗冈萨雷斯

6

希望它的工作

SET foreign_key_checks = 0; 删除表table name; SET foreign_key_checks = 1;


是的,它的工作原理,作为多次,它已经提到过;-)
阿尔瓦罗·冈萨雷斯

1

在Rails上,您可以使用进行以下操作rails console

connection = ActiveRecord::Base.connection
connection.execute("SET FOREIGN_KEY_CHECKS=0;")


0

我找到了一个简单的解决方案,导出数据库,在文本编辑器中编辑要编辑的内容,然后导入。完成


4
这是一个有趣的解决方案,可能实际上不应该发生。相反,任何需要更改的内容都应该通过DBMS完成。在文本编辑器中编辑数据库转储似乎是解决问题的成熟途径。
布兰登·安扎尔迪

1
我不太了解您的兴趣。转储数据库,删除CREATE TABLE代码并再次加载转储...不会使MySQL删除表。如果您要恢复新数据库中的转储...如果要像我一样清除所有表,则新创建的数据库将已经为空。如果要保留一些表,SET FOREIGN_KEY_CHECKS=0此处各处所提到的解决方法都可以很好地工作,并且更简单。而且您可能也不需要编辑转储,因为新的数据副本可能没有不同步的数据字典。
阿尔瓦罗·冈萨雷斯

-1

无法删除或更新父行:外键约束失败(table1user_role,CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY(user_id)参考userid))

我分两个简单步骤进行了操作。首先我删除子表中的子行

mysql>从table2中删除,其中role_id = 2 && user_id = 20;

查询正常,1行受影响(0.10秒)

第二步是删除父对象

从表1中删除,其中id = 20;

查询正常,1行受影响(0.12秒)

通过这种方式我解决了问题,即删除子项然后删除父项

我希望你明白了。:)


请再次阅读问题。您无法删除不存在的表。
阿尔瓦罗·冈萨雷斯

在这种情况下,我们可以删除外键约束,然后尝试删除表。我们可以像这样删除外键ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Aadil Masavir
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.