ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个奇怪的问题。我正在尝试将外键添加到一个引用另一个表的表中,但由于某种原因它失败了。由于我对 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
您还可以发布导致错误的插入/更新命令吗?
添加此外键时,您的表是空的吗?
尝试运行此查询以查看是否有任何不是真实 id 的 sourcecode_id: SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes AS tmp);
谢谢 Zed,这是其中一张表中有数据的问题。现在考虑一下,它失败是有道理的,因为有些东西引用了不存在的项目,但我永远不会猜到这一点。谢谢!
如果表为空,为什么会失败?

J
Jannis

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

这是一个可以找到这些 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。或者,如果 sourcecode_id 中不允许使用 null,则删除这些行或将这些缺失值添加到 sourcecodes 表中。
我也是这么想的,但是对我来说 SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULL 没有返回任何东西,所以问题出在其他地方!?
啊,这对我来说是个问题。我试图运行 UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;,它根本不涉及外键,所以我很困惑。但是我的联系人表缺少自动化表所引用的一些记录这一事实导致它抛出此“错误代码:1452。无法添加或更新子行:外键约束失败”。
M
Mostafa Norzade

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

foreign_key_checks 是有原因的。如果由于违反约束而无法添加外键,则应先更正数据。关闭检查然后添加密钥会使您处于不一致的状态。外键检查会增加开销,如果您不想使用它们,请改用 myisam。
@AbuSadatMohammedYasin 不,不应该:问题问“发生了什么”,而这个答案根本没有试图解释它。正如 cs_alumnus 所提到的,还有一个更大的问题:所有应该引用另一个表中的另一个值的新值(作为 Foreign 键应该做的)可能指向任何内容,从而产生不一致的状态。 Cayetano's short and effective explanation 允许您在创建约束之前找到应该更新的值,这样您就不会对应该返回应该存在的值的查询感到惊讶!
在我的情况下,父表的列长度为 25 个字符,而子表的列长度为 30 个字符。将字符长度增加到 30 为我修复了它。感谢您为我指明正确的方向。
R
Ryan Ward

使用 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 运算符快得多,并且更容易构造和重复。


所以,如果我理解正确,我们可以将外键添加到已经有数据的表中,但前提是父表中的每一行都存在子行?如果父表中的每一行都没有子行(这是您的查询发现的),则外键脚本将失败。
@Vincent 如果父表是指被引用的表,那么是的!因此,使用 Cayetano 的选择,您可以在添加新约束 (FK) 之前从“子”表中更新/删除所有行。一旦它们都指向“another_table”中的值,那么你就可以开始了!
C
Community

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

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


无需截断所有内容。 “UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)”就足够了。或者,如果“sourcecode_id”中不允许为 null,则删除这些行或将这些缺失值添加到“sourcecodes”表中。
有时,如果数据增加自动增量 PK,它会强制您截断。
@ShankarDamodaran 不确定为什么截断表格有效,但这个解决方案对我来说效果很好。我能够让我的关系正常工作......谢谢!
@MizAkita 它之所以有效,是因为它删除了另一个表中没有相应值的行,从而允许创建新的约束。如果您只是找到这些行并更新或删除它们(如 Cayetano's suggestion),则无需删除其他行...
@Armfoot - 使用外键将第一行添加到表时遇到了这个问题。所以我没有要搜索的行。
M
Mostafa Norzade

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

您必须确保您的两个表都是 InnoDB。如果其中一个表,即引用表是 MyISAM,则约束将失败。

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

f
fyrye

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

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

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


M
Mostafa Norzade

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

子列中是否存在父列中不存在的值(如果子列可以为空,则为 NULL) 子列和父列是否具有相同的数据类型?您引用的父列上是否有索引? MySQL 似乎出于性能原因需要这个 (http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html) 而这个为我解决了这个问题:两张表是否相同整理?

我有一张 UTF-8 表,另一张表是 iso-something。那没有用。将 iso-table 更改为 UTF-8 排序规则后,可以毫无问题地添加约束。就我而言,phpMyAdmin 甚至没有在下拉菜单中以 iso-encoding 显示子表以创建外键约束。


M
Mostafa Norzade

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

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

删除您尝试为其设置 FK 约束的列。再次添加它并将其默认值设置为 NULL。尝试再次为其设置外键约束。


M
Mostafa Norzade

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


V
VHanded

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


r
rink.attendant.6

尝试这个

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;

M
MarthyM

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

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 语法方面并不是特别出色,但这对我来说总是孤立的问题。


M
MarthyM

清空两个表的数据并运行命令。它会起作用的。


VHanded 3 年前给出了同样的答案。让我们希望表格中没有任何重要数据......
t
twigg

我在使用 Laravel 和 eloquent 时遇到此错误,尝试建立外键链接会导致 1452。问题是链接表中缺少数据。

请在此处查看示例:http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/


T
TrebledJ

你只需要回答一个问题:

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

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

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

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

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


C
CesareoAguirre

我正在准备这个解决方案,这个例子可能会有所帮助。

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

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

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

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

希望这可以帮助。


mysql> 插入电子邮件(电子邮件)值('xxx@yyy.com'); mysql> 插入 ndtc (ndtc, 年, 月) 值 ('1111222233334444', '2000', '01'); mysql> 插入客户(名词、apellidos、telefono、idNDTC、idEmail)值('myname'、'myapp'、'5555555555'、1,1);
K
Kingsley Mitchell

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

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


F
Fouad Mekkey

你可以试试这个例子

 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,只需取消选中启用外键检查

https://i.stack.imgur.com/xrQER.png

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


n
naXa stands with Ukraine
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

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


a
akelec

我遇到了同样的问题并找到了解决方案,将 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 已经执行了这个查询!


S
Shamal Sabah

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

它对我有用。