Mysql错误1452 - 无法添加或更新子行:外键约束失败

Zim*_*Zim 234 mysql foreign-keys mysql-error-1452

我有一个奇怪的问题.我正在尝试将一个外键添加到一个引用另一个表的表中,但由于某种原因它失败了.由于我对MySQL的了解有限,唯一可能怀疑的是在不同的表上有一个外键引用我想要引用的那个.

这是我的表关系的图片,通过phpMyAdmin:Relationships生成

SHOW CREATE TABLE对两个表都进行了查询,sourcecodes_tags是带有外键的表,sourcecodes是引用的表.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

如果有人能告诉我这里发生了什么,我没有正式的训练或任何与MySQL :)

谢谢.

编辑:这是生成错误的代码:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
Run Code Online (Sandbox Code Playgroud)

nos*_*nos 224

您的sourcecodes_tags表很可能包含表中sourcecode_id不再存在的值sourcecodes.你必须先摆脱那些.

这是一个可以找到这些ID的查询:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;
Run Code Online (Sandbox Code Playgroud)


小智 96

我的mysql数据库遇到了同样的问题,但最后我得到了一个适合我的解决方案.
因为在我的表中从mysql的角度来看一切都很好(两个表都应该使用Innodb引擎,每个列的数据类型应该是参与外键约束的相同类型).
我所做的只是禁用外键检查,然后在执行外键操作后启用它.
我采取的步骤:

SET foreign_key_checks = 0;
Run Code Online (Sandbox Code Playgroud)

  • foreign_key_checks是有原因的.如果由于违反约束而无法添加外键,则应首先更正数据.关闭检查然后添加密钥会使您处于不一致状态.外键检查会增加开销,如果您不想使用它们,请使用myisam代替. (48认同)
  • @AbuSadatMohammedYasin不,它不应该:问题是"发生了什么",这个答案根本就不试图解释它.正如cs_alumnus所提到的,存在一个更大的问题:应该在另一个表中引用另一个值的所有新值(作为**外部**键应该这样做)可能指向什么,创建一个不一致的状态.[Cayetano简短而有效的解释](http://stackoverflow.com/a/6193053/1326147)允​​许您在创建约束之前找到应更新的值,这样您就不会对应该返回值的查询感到惊讶存在! (5认同)

Rya*_*ard 55

使用NOT IN以找到约束制约:

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)
Run Code Online (Sandbox Code Playgroud)

所以,更具体地说:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)
Run Code Online (Sandbox Code Playgroud)

编辑:INNOT IN运营商被称为是比快很多JOIN运营商,以及更容易构建,并重复.


Sha*_*ran 23

截断表,然后尝试添加FK约束.

我知道这个解决方案有点尴尬,但它确实可以100%工作.但我同意这不是处理问题的理想解决方案,但我希望它有所帮助.

  • 无需截断所有内容."UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN(SELECT id FROM sourcecodes)"应该足够了.或者,如果"sourcecode_id"中不允许null,则删除这些行或将这些缺失值添加到"sourcecodes"表中. (4认同)
  • @ShankarDamodaran不确定为什么截断表可行,但这个解决方案对我来说效果很好.我能够让我的人际关系得以发挥......谢谢! (2认同)

zmo*_*eca 16

对我来说,这个问题有点不同,超级易于检查和解决.

您必须确保表的两个是InnoDB.如果其中一个表(即参考表是MyISAM),则约束将失败.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)


fyr*_*rye 14

如果child.column的值已经为0且parent.id值为0,那么在将parent.id的外键设置为child.column时也会发生这种情况.

您需要确保每个child.column为NULL或具有parent.id中存在的值

现在,我读到了nos写的声明,这就是他正在验证的内容.


Mic*_*wig 14

我今天遇到了同样的问题.我测试了四件事,其中一些已经在这里提到:

  1. 您的子列中是否存在父列中不存在的值(除了NULL,如果子列可以为空)

  2. 子列和父列具有相同的数据类型吗?

  3. 您引用的父列上是否有索引?出于性能原因,MySQL似乎需要这个(http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)

  4. 这个问题解决了我:两个表都有相同的校对吗?

我在utf-8中有一个表,在iso-something中有一个表.那没用.将iso-table更改为utf-8整理后,可以毫无问题地添加约束.在我的例子中,phpMyAdmin甚至没有在用于创建外键约束的下拉列表中以iso编码显示子表.


Mil*_*lad 7

似乎有一些无效值的列,如0,这不是一个有效的外键,所以MySQL不能为它设置外键约束.

您可以按照以下步骤操作:

  1. 删除您尝试为其设置FK约束的列.

  2. 再次添加它并将其默认值设置为NULL.

  3. 尝试再次为它设置外键约束.


小智 5

我遇到了同样的问题,我检查了我的表行,发现与我想要定义为外键的字段值有些不兼容.我纠正了这些价值,再次尝试,问题解决了.