从一个表复制到另一个表,如何对整个数据集而不是单独的行强制执行外键检查?
Posted
技术标签:
【中文标题】从一个表复制到另一个表,如何对整个数据集而不是单独的行强制执行外键检查?【英文标题】:Copying from one table to other, how to enforce foreign key check on the whole data set but not on separate rows? 【发布时间】:2018-03-06 16:13:05 【问题描述】:我正在使用 mysql。假设我有一个表 hierarchy
有两列:id
、parent_id
。
parent_id
指的是同一张表的另一行的id
,所以我那里有外键。
hierarchy
表包含一些数据,但它们现在不相关。
我还有另一个名为 new_hierarchy_entries
的表具有相同的列,但没有设置外键限制。
new_hierarchy_entries
包含:
id parent_id
2 1
1 null
现在我想将所有行从new_hierarchy_entries
复制到hierarchy
。当我天真地奔跑时:
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries
我收到错误:无法添加或更新子行:外键约束失败(my_db.hierarchy
, CONSTRAINT hierarchy_ibfk_2 FOREIGN KEY (parent_id) REFERENCES hierarchy
(id))
当然,如果逐行插入,第一行(id=2,parent=1)就无法插入,因为表hierarchy
中没有id=1的行。
另一方面,如果一次添加所有行,则将满足约束条件。那么如何复制行以确保在复制后满足约束条件,但在复制时可能不满足约束条件?
按id
对new_hierarchy_entries
的行进行排序将无济于事。我不能假设 parent_id < id
在同一行。
按层次结构对new_hierarchy_entries
的行进行排序(使用树术语,先给我叶子,然后给我他们的父母等)会有所帮助,但我不确定如何在 MySQL 查询中做到这一点。
我的想法是暂时关闭 FOREIGN_KEY_CHECKS。但后来我可以插入不一致的数据,但我不会发现。打开 FOREIGN_KEY_CHECKS 不会使数据库检查所有数据的一致性。反正会占用太多资源。
【问题讨论】:
【参考方案1】:这很棘手。在启用 FOREIGN_KEY_CHECKS 后,我不知道有什么方法可以让 MySQL 重新检查外键引用。
您可以检查自己是否有孤立行,如果有,请回滚。
BEGIN;
SET SESSION FOREIGN_KEY_CHECKS=0;
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries;
SET SESSION FOREIGN_KEY_CHECKS=1;
SELECT COUNT(*) FROM hierarchy AS c
LEFT OUTER JOIN hierarchy AS p ON p.id=c.parent_id
WHERE p.id IS NULL;
-- if count == 0 then...
COMMIT;
-- otherwise ROLLBACK and investigate the bad data
另一种可能性是将 INSERT 与 IGNORE 选项一起使用,这将跳过失败的行。然后在循环中重复相同的语句,只要您看到“受影响的行数”超过 0。
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
...
【讨论】:
以上是关于从一个表复制到另一个表,如何对整个数据集而不是单独的行强制执行外键检查?的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从一个 BigTable 表复制到另一个 BigTable 表