如何在数据库中复制实体树

时间:2013-09-19 18:05:08

标签: sql sql-server tsql

我有一个非常标准的关系数据情况,其中有一个带有子实体的根实体(和相应的表)。这些孩子有儿童实体等等约6个等级。每个级别都有很多孩子与父母之间的关系。我想编写一个有效复制根实体及其所有子实体的过程(以递归方式复制子项的子项),为每个实体创建新实体,同时将每个实体存储在各自的表中。

我知道这可以用嵌套游标完成,但我不想这样做。我知道有一个更优雅的解决方案,我只需要帮助创建它。我有一种感觉,解决方案在于OUTPUT子句和MERGE语句的组合。

如果可以,请为新手SQL开发人员级别量身定制答案。我将需要一个解释或链接到您使用的任何结构的解释,这些结构超出了基本的SELECT INSERT UPDATE和DELETE。

感谢您的时间。

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

我假设您要复制表层次结构中的数据子集。按层次结构,我指的是在明显意义上通过外键相互关联的表。例如,Customers将是一个根表,Orders是其子项,OrderDetails是另一个子项(在第3级)。

首先,我们复制层次结构的根表:

MERGE RootTable as target
USING (
 SELECT *
 FROM RootTable
 WHERE SomeCondition
) AS src
ON 1=2 -- this is so that all rows that do not match will be added
WHEN NOT MATCHED THEN INSERT (AllColumns) VALUES (AllColumns)
OUTPUT src.ID as OldID, INSERTED.ID as NewID INTO #RootTableMapping

现在我们在#RootTableMapping中对根表的复制源和复制目标ID进行了1比1的映射。此外,还复制了所有根行。

我们现在需要复制所有子表。这是一个声明:

MERGE ChildTable as target
USING (
 SELECT *, #RootTableMapping.NewID AS NewParentID
 FROM ChildTable
 JOIN #RootTableMapping ON ChildTable.RootID = #RootTableMapping.OldID
 WHERE SomeCondition
) AS src
WHEN NOT MATCHED THEN INSERT (AllColumns, RootID) VALUES (AllColumns, NewParentID)

这里,我们为每个子行获取克隆的根表行的ID,以便我们可以链接层次结构。为此,我们使用#RootTableMapping。我们复制所有未修改的列,除了我们用映射中的NewID替换的父类的ID。

每个子表都需要一个这样的MERGE语句。通过添加其他连接,该概念还扩展到具有2个以上级别的层次结构。除底层以外的所有级别都必须记录复制源ID到复制目标ID的映射,以允许下面的下一层获取新ID。

如果我没有说清楚一切,请随意提出进一步的问题。我知道这是一个粗略的草图。