从一个表复制到另一个表,如何对整个数据集执行外键检查,但不对单独的行执行?

时间:2018-03-06 16:13:05

标签: mysql sql

我正在使用MySQL。我们假设我有一个包含两列的表hierarchyidparent_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的行。

另一方面,如果一次添加所有行,则将满足约束。那么如何以这样的方式复制行,以确保复制后满足约束,但复制时可能不满足?

new_hierarchy_entries排序id行无济于事。我不能假设parent_id < id在同一行。

按层次结构对new_hierarchy_entries行进行排序(使用树术语,先给我留下,然后让他们的父母等等)会有所帮助,但我不确定如何在MySQL查询中这样做。< / p>

我想暂时关闭FOREIGN_KEY_CHECKS。但后来我可以插入不一致的数据,我不会发现。打开FOREIGN_KEY_CHECKS并不会使数据库检查所有数据的一致性。无论如何,这需要太多的资源。

1 个答案:

答案 0 :(得分:0)

这很棘手。启用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

另一种可能性是使用带有IGNORE选项的INSERT,它将跳过失败的行。然后在循环中重复相同的语句,只要您看到“受影响的行”超过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;
...