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

Posted

技术标签:

【中文标题】MySQL - 无法添加或更新子行:外键约束失败【英文标题】:MySQL - Cannot add or update a child row: a foreign key constraint fails 【发布时间】:2012-10-09 14:50:00 【问题描述】:

这似乎是一个常见的错误,但我这辈子都想不通。

我在 mysql 中有一组 InnoDB 用户表,它们通过外键绑定在一起;父表user 和一组存储电子邮件地址、操作等的子表。这些都通过外键uid 与父表user 绑定,其中包含所有父键和子键是int(10)

所有子表都有一个uid 值,外键约束指向user.uid,并设置为ON DELETE CASCADEON UPDATE CASCADE

当我从user 中删除用户时,所有子约束条目都将被删除。但是,当我尝试更新 user.uid 值时,会导致以下错误,而不是将 uid 更改级联到子表:

#1452 - Cannot add or update a child row: a foreign key constraint fails (`accounts`.`user_email`, CONSTRAINT `user_email_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE CASCADE ON UPDATE CASCADE)

我有一种感觉,我必须在这里遗漏一些明显的东西。使用user_email 删除键约束并尝试更新user 中的值会导致相同的错误,但对于下一个按字母顺序排列的user 子表,所以我不认为这是特定于表的错误。

编辑:

添加来自SHOW ENGINE INNODB STATUS的结果:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
121018 22:35:41 Transaction:
TRANSACTION 0 5564387, ACTIVE 0 sec, process no 1619, OS thread id 2957499248 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
17 lock struct(s), heap size 2496, 9 row lock(s), undo log entries 2
MySQL thread id 3435659, query id 24068634 localhost root Updating
UPDATE `accounts`.`user` SET `uid` = '1' WHERE `user`.`uid` = 306
Foreign key constraint fails for table `accounts`.`user_email`:
,
  CONSTRAINT `user_email_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE CASCADE ON UPDATE CASCADE
Trying to add in child table, in index `uid` tuple:
DATA TUPLE: 2 fields;
...
A bunch of hex code

But in parent table `accounts`.`user`, in index `PRIMARY`,
the closest match we can find is record:
...
A bunch of hex code

【问题讨论】:

投票将其移至 dba。 【参考方案1】:

我通过将以下代码添加到 SQL 代码的开头解决了我的“外键约束失败”问题(这是用于将值导入表)

SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT;
SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS;
SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION;
SET NAMES utf8;
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0; 

然后将此代码添加到文件末尾

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT;
SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS;
SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION;
SET SQL_NOTES=@OLD_SQL_NOTES; 

【讨论】:

救生员,谢谢 它在做什么? @Timo 这告诉数据库 IGNORE uniqueforeign key 约束。基本上,INSERTUPDATE 语句是绕过这些规则完成的。你最终可能会搞砸一切。仅在针对特定操作并且您 100% 确定您将要做的事情真的没问题时才这样做。【参考方案2】:

由于您没有给出表定义,因此很难猜测。但看起来您正在尝试修改子表中的外键。 AFAIK,这是非法的,您可以从父表修改它,但不能从子表修改。

考虑这个例子:

CREATE TABLE parent (
  parent_id INT NOT NULL,
  parent_data int,

  PRIMARY KEY (parent_id)
) ENGINE=INNODB;

CREATE TABLE child1 (
  child1_id INT,
  child1_data INT,
  fk_parent_id INT,

  INDEX par_ind1 (fk_parent_id),

  FOREIGN KEY (fk_parent_id)
    REFERENCES parent(parent_id)
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE=INNODB;

CREATE TABLE child2 (
  child2_id INT,
  child2_data INT,
  fk_parent_id INT,

  INDEX par_ind2 (fk_parent_id),

  FOREIGN KEY (fk_parent_id)
    REFERENCES parent(parent_id)
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE=INNODB;

INSERT INTO parent
  (parent_id, parent_data)
  VALUES
  (1, 11),
  (2, 12);

INSERT INTO child1
  (child1_id, child1_data, fk_parent_id)
  VALUES
  (101, 1001, 1),
  (102, 1002, 1),
  (103, 1003, 1),
  (104, 1004, 2),
  (105, 1005, 2);

INSERT INTO child2
  (child2_id, child2_data, fk_parent_id)
  VALUES
  (106, 1006, 1),
  (107, 1007, 1),
  (108, 1008, 1),
  (109, 1009, 2),
  (110, 1010, 2);

那么这是允许的:

UPDATE parent
  SET parent_id = 3 WHERE parent_id = 2;

SELECT * FROM parent;
SELECT * FROM child1;
SELECT * FROM child2;

但这不是,因为它从子表中修改了父 fk:

UPDATE child1
  SET fk_parent_id = 4 WHERE fk_parent_id = 1;

它得到一个与你的错误非常相似的错误:

Cannot add or update a child row: a foreign key constraint fails (`db_2_b43a7`.`child1`, CONSTRAINT `child1_ibfk_1` FOREIGN KEY (`fk_parent_id`) REFERENCES `parent` (`parent_id`) ON DELETE CASCADE ON UPDATE CASCADE):

【讨论】:

谢谢。我正在更新父表 - 请参阅我发布的转储中的查询:UPDATE `accounts`.`user` SET `uid` = '1' WHERE `user`.`uid` = 306user 是父表,会触发这个错误。 你能发布更多关于你的架构的信息吗?或者修改上面的例子,让你得到同样的错误? 我们应该怎么做才能在不影响父表的情况下更新子表外键 取决于你想要什么。如果您不想要该约束,请不要将其标记为外键,或者使用引用选项 NO ACTION。这可能值得自己提出问题。 其实有一个办法但是我不喜欢,就是SET foreign_key_checks = 0;然后更新外键然后 SET foreign_key_checks = 1;【参考方案3】:

我在表上创建外部约束时遇到了同样的问题。解决此问题的简单方法是首先备份您的父表和子表,然后截断子表并再次尝试建立关系。希望这能解决问题。

【讨论】:

【参考方案4】:

尽管这已经很老了,但只是插话说@Sidupac 的答案中有用的是FOREIGN_KEY_CHECKS=0

当您使用为您管理数据库架构的东西(在我的情况下为 JPA)时,此答案不是一个选项,但问题可能是您的表中存在“孤立”条目(引用可能没有的外键存在)。

当您将 MySQL 表从 MyISAM 转换为 InnoDB 时,通常会发生这种情况,因为引用完整性实际上与前者无关。

【讨论】:

【参考方案5】:

在一项不相关的任务中,我最近在MySQL Workbench 中启动了我们的 MySQL 数据库,当查看上述表的表关系时,我注意到我以前不知何故错过的“重复”和/或虚假关系(它们不是'没有出现在 phpMyAdmin FWIW 中)。删除这些额外的关系会立即解决问题。

【讨论】:

【参考方案6】:

这样的更新错误可能是由字符集和排序规则的差异引起的,因此请确保两个表的它们相同。

【讨论】:

【参考方案7】:

我对此的解决方法是需要在父表之前填充我的子表。

我有两个表:通过电子邮件地址链接的 UserDetails 和 Login。因此,在插入登录表之前,我必须先插入 UserDetails:

insert into UserDetails (Email, Name, Telephone, Department) values ('Email', 'Name', 'number', 'IT');

然后:

insert into Login (UserID, UserType, Email, Username, Password) VALUES (001, 'SYS-USR-ADMIN', 'Email', 'Name', 'Password')

【讨论】:

【参考方案8】:

我遇到过这个问题,解决方案是确保子字段中的所有数据都与父字段匹配

例如,您想将(出勤)表内的外键添加到列(employeeName)

父是(employees) 表,(employeeName) 列

出席.employeeName 中的所有数据必须与employee.employeeName 匹配

【讨论】:

【参考方案9】:

我遇到了同样的问题,但是当我仔细观察时发现,这是因为我试图在为该键分配主键值之前将外键值放入表中。例如 我有两个表“customers”和“films”,“cust_id”和“film_id”分别是主键。 “客户”与“电影”有一对多的关系,所以我在“电影”表中将“cust_id”作为外键。但我试图首先将值放在“电影”表中,所以我遇到了这个问题。

【讨论】:

【参考方案10】:

希望这将有助于在将 CSV 数据导入相关表时遇到相同错误的任何人。在我的情况下,父表没问题,但是在将数据导入包含外键的子表时出现错误。在临时删除子表上的外键约束后,我设法导入数据并惊讶地发现 FK 列中的一些值的值为 0 (显然这导致了错误,因为父表没有PK 列中的此类值)。原因是,我的 CSV 列中 FK 列之前的数据包含逗号(我用作字段分隔符)。更改我的 CSV 文件的分隔符解决了这个问题。

【讨论】:

以上是关于MySQL - 无法添加或更新子行:外键约束失败的主要内容,如果未能解决你的问题,请参考以下文章

ERROR 1452:无法添加或更新子行:外键约束失败

如何修复部署到Linux服务器后MySql中的“无法添加或更新子行:外键约束失败”?

Hibernate:无法添加或更新子行:外键约束失败

无法添加或更新子行:外键约束失败

外键 Laravel 8 foreignId + 约束 - 无法添加或更新子行:外键约束失败

无法添加或更新子行:外键约束失败