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


237

我有一个奇怪的问题。我正在尝试向一个引用另一个表的表添加外键,但是由于某种原因它失败了。以我对MySQL的有限了解,唯一可能令人怀疑的是,另一张表上有一个外键引用了我要引用的表。

我已经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

这是生成错误的代码:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

2
您还可以发布导致错误的插入/更新命令吗?
Zed

64
添加此外键时,表是否为空?
Zed

12
尝试运行此查询以查看是否有不是真实ID的sourcecode_id:SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN(SELECT id FROM源代码AS tmp);
Zed

11
感谢Zed,这就是其中一张表中有数据的问题。现在考虑一下,它之所以失败是有道理的,因为有些东西正在引用不存在的项,但是我从来没有想过。谢谢!
Zim

2
如果表为空,为什么会失败?
theblackpearl 2014年

Answers:


226

您的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;

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)应该有助于摆脱这些ID。或者,如果null不允许使用sourcecode_id,则删除那些行或将那些缺少的值添加到sourcecodes表中。
naXa

我当时的想法是一样的,但是,对我来说SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULL什么也不会退,所以问题出在其他地方!
Meloman '17

嗯,这是我的问题。我试图运行UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;,根本不涉及外键,所以感到很困惑。但是,我的联系人表缺少自动化表所引用的某些记录的事实导致它抛出此“错误代码:1452。无法添加或更新子行:外键约束失败”。
瑞安

99

我的MySQL数据库有同样的问题,但是最后,我得到了一个对我有用的解决方案。
因为在我的表中,从mysql的角度来看,一切都很好(两个表都应使用InnoDB引擎,并且每一列的数据类型应为参与外键约束的相同类型)。
我唯一要做的就是禁用外键检查,然后在执行外键操作之后启用它。
我采取的步骤:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;

49
foreign_key_checks在那里是有原因的。如果由于违反了约束而无法添加外键,则应首先更正数据。关闭检查然后添加密钥会使您处于不一致状态。外键检查会增加开销,如果您不想使用它们,请改用myisam。
cs_alumnus 2014年

5
@AbuSadatMohammedYasin不,它不应该:这个问题问“发生了什么事”,而这个答案并没有试图解释它。正如cs_alumnus提到的那样,存在一个更大的问题:应该引用另一个表中另一个值的所有新值(如键应做的那样)可能指向无内容,从而产生不一致的状态。Cayetano简短有效的说明使您能够在创建约束之前找到应更新的值,这样您就不会对应该返回应该存在的值的查询感到惊讶!
Armfoot

55

使用NOT IN以找到约束制约

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

因此,更具体地说:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

编辑:INNOT IN运算符被认为比JOIN运算符要快得多,并且也容易构造和重复。


1
因此,如果我正确理解了这一点,我们可以将外键添加到已经有数据的表中,但前提是父表中的每一行都存在一个子行?如果父表中的每一行都没有子行(这是查询发现的内容),那么外键脚本将失败。
文森特2015年

@Vincent如果由父表表示要引用该表,则可以!因此,通过Cayetano的select,您可以在添加新约束(FK)之前从“子”表中获取所有需要更新/删除的行。一旦它们全部指向“ another_table”中的值,那么您就可以开始了!
Armfoot

23

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

我知道此解决方案有点尴尬,但确实可以100%使用。但是我同意这不是解决问题的理想解决方案,但我希望它能有所帮助。


4
无需截断所有内容。“ UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN(从源代码中选择SELECT ID)”就足够了。或者,如果“ sourcecode_id”中不允许使用null,则删除这些行或将那些缺少的值添加到“ sourcecodes”表中。
Torben

1
有时,如果数据使自动递增PK递增,则会迫使您截断。
弗朗索瓦·布雷顿

2
@ShankarDamodaran不知道为什么要删节表,但是此解决方案对我来说效果很好。我能够使我的人际关系正常运转...谢谢!
MizAkita 2014年

@MizAkita之所以起作用,是因为它删除了另一个表中没有相应值的行,从而允许创建新的约束。如果您只是找到这些行并更新或删除它们(如Cayetano的建议),则无需删除其他行...
Armfoot

@Armfoot-用外键将第一行添加到表时遇到了这个问题。所以我没有要搜索的行。
克鲁特卡'16

16

对我来说,这个问题有点不同,而且超级容易检查和解决。

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

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

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

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

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


14

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

  1. 子列中是否存在父列中不存在的任何值(如果子列可为空,则为NULL)

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

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

  4. 这个为我解决了:两个表是否具有相同的排序规则?

我在UTF-8中有一张桌子,在异物中有另一张桌子。那没用。将iso-table更改为UTF-8归类后,可以毫无问题地添加约束。就我而言,phpMyAdmin甚至没有在创建外键约束的下拉菜单中以iso编码显示子表。


7

似乎第0行的列存在一些无效值,该值不是有效的外键,因此MySQL无法为其设置外键约束。

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

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

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

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


5

我遇到了同样的问题,我检查了表中的行,发现与我想定义外键的字段的值不兼容。我更正了这些值,然后再试一次,问题就解决了。


4

我最终删除了表中的所有数据,然后再次运行alter。有用。这不是一个出色的解决方案,但可以节省很多时间,尤其是您的应用程序仍处于开发阶段,没有任何客户数据。


4

试试这个

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;

2

我在三个不同的时间遇到​​了同样的问题。在每种情况下,都是因为我的一个(或多个)记录不符合新的外键。在尝试添加键本身之前,您可能希望更新现有记录以遵循外键的语法约束。以下示例通常应隔离问题记录:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

AND (candidate key) <> (next proposed foreign key value)在查询中针对外键中的每个值重复此操作。

如果您有大量的记录,这可能会很困难,但是如果您的表相当小,则不要花费太长时间。我对SQL语法并不感到惊讶,但这始终使我感到困扰。




1

我正在准备此解决方案,此示例可能会有所帮助。

我的数据库有两个表(电子邮件和credit_card),它们的ID是主键。另一个表(客户端)将此表ID称为外键。我有理由将电子邮件与客户数据分开。

首先,我为引用的表(电子邮件,credit_card)插入行数据,然后为每个表获取ID,在第三张表(客户端)中需要这些ID。

如果您不首先在被引用的表中插入行,则当您在第三个表中插入引用外键的新行时,MySQL将无法进行对应。

如果您首先为引用表插入引用行,则引用外键的行不会发生错误。

希望这可以帮助。


mysql>插入电子邮件(email)值('xxx@yyy.com'); mysql>插入ndtc(ndtc,年,月)值('1111222233334444','2000','01'); mysql>插入cliente(nombres,apellidos,telefono,idNDTC,idEmail)值('myname','myapp','5555555555',1,1);
SubstanceMX

1

确保该值在另一个表中,否则您将在分配的对应列中收到此错误。

因此,如果已分配列已分配给另一个表的行ID,请确保该表中有一行,否则将出现此错误。


1

你可以试试这个例子

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

注意:如果您使用的是phpmyadmin,请取消选中启用外键检查

作为 例子 在此处输入图片说明

希望这个解决方案可以解决您的问题:)


1

您只需要回答一个问题:

您的表已经存储数据了吗?(特别是该表包含外键。)

如果答案是肯定的,那么您唯一需要做的就是删除所有记录,然后就可以将任何外键添加到表中了。

删除指令:从子表(包括外键表)到父表。

数据输入后不能添加外键的原因是由于表的不一致,您将如何处理以前填充数据的表上的新外键?

如果答案是否定的,则按照其他说明进行操作。


0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

应该有助于摆脱这些ID。或者,如果null不允许使用sourcecode_id,则删除那些行或将那些缺少的值添加到sourcecodes表中。


0

我遇到了同样的问题,找到了解决方法,NULL而不是NOT NULL放在外键列上。这是一个查询:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

MySQL已执行此查询!


0

就我而言,我创建了一个具有相同结构的新表,创建了与其他表的关系,然后从出现问题的旧表中提取了CSV数据,然后将CSV导入到新表中并禁用了外键检查并禁用了导入中断,我的所有数据都成功插入到没有问题的新表中,然后删除了旧表。

它为我工作。

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.