【问题标题】:Insert self-referencing data into copy table将自引用数据插入复制表
【发布时间】:2014-07-21 12:06:48
【问题描述】:

我的表上有一个自引用外键约束。因为我正在转换架构,所以我想将现有数据复制到具有(或多或少)相同结构的新表中:

CREATE TABLE test(
  id INT NOT NULL PRIMARY KEY,
  parent INT,
  FOREIGN KEY (parent) REFERENCES test(id)
);

CREATE TABLE copy(
  id INT NOT NULL PRIMARY KEY,
  parent INT,
  FOREIGN KEY (parent) REFERENCES copy(id) 
);

但是,当inserting the data:

INSERT INTO copy(id, parent) SELECT id, parent FROM test;

MySQL 给出了常见的完整性错误:

Error Code: 1452. Cannot add or update a child row:
    a foreign key constraint fails (`test`.`copy`, CONSTRAINT `copy_ibfk_1`
    FOREIGN KEY (`parent`) REFERENCES `copy` (`id`))

似乎 MySQL 在插入每一行后检查约束,而不是在整个插入后检查它。完全相同的例子works fine in PostgreSQL

有没有其他方法可以插入这些数据,还是我坚持要分两步这样做?

INSERT INTO copy(id) SELECT id FROM test;
UPDATE copy
JOIN test ON test.id = copy.id
SET copy.parent = test.parent;

【问题讨论】:

  • 使用 MySQL,您只有这两个选项:禁用约束(如 VMai 所示)或在一个事务中执行插入/更新(如您现在所做的那样)。

标签: mysql sql foreign-keys foreign-key-relationship


【解决方案1】:

你可以使用

SET FOREIGN_KEY_CHECKS=0;

在您的 INSERT 和之前

SET FOREIGN_KEY_CHECKS=1;

在禁用外键约束的检查之后,你不必担心插入的顺序:

查看foreign_key_checks的文档

foreign_key_checks

如果设置为 1(默认值),InnoDB 表的外键约束 被检查。如果设置为 0,则忽略此类约束。 [...] 通常 您在正常操作期间启用此设置,以强制执行 参照完整性。禁用外键检查可能很有用 以不同于所要求的顺序重新加载此类表 他们的父母/子女关系。请参阅第 14.6.6 节,“InnoDB 和 外键约束”。 [...]

注意

将 foreign_key_checks 设置为 1 不会触发对 现有的表数据。因此,添加到表中的行同时 foreign_key_checks = 0 不会验证一致性。

CREATE TABLE test(
  id INT NOT NULL PRIMARY KEY,
  parent INT,
  FOREIGN KEY (parent) REFERENCES test(id) 
);

CREATE TABLE copy(
  id INT NOT NULL PRIMARY KEY,
  parent INT,
  FOREIGN KEY (parent) REFERENCES copy(id) 
);

INSERT INTO test(id, parent) VALUES(1, null);
INSERT INTO test(id, parent) VALUES(2, 1);
INSERT INTO test(id, parent) VALUES(3, null);
INSERT INTO test(id, parent) VALUES(4, 2);
UPDATE test SET parent=3 WHERE id=1;

SET FOREIGN_KEY_CHECKS=0;

-- Success with MySQL
INSERT INTO copy(id, parent) SELECT id, parent FROM test;

SET FOREIGN_KEY_CHECKS=1;

你更新的小提琴:http://sqlfiddle.com/#!2/ae623/1

【讨论】:

  • MySQL 是否对SET 命令提供事务支持? (我假设没有)换句话说:如果事务在插入之前/期间/之后失败会发生什么?我宁愿不放弃约束保证...
  • @r0estir0bbe 我认为一次性工作没有任何问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 2020-09-03
  • 2013-05-26
  • 1970-01-01
相关资源
最近更新 更多