【问题标题】:How to copy an entity tree in database如何在数据库中复制实体树
【发布时间】:2013-09-24 23:10:46
【问题描述】:

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

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

如果可以,请根据 SQL 开发新手级别调整您的答案。对于您使用的超出基本 SELECT INSERT UPDATE 和 DELETE 的任何结构,我需要解释或解释的链接。

感谢您的宝贵时间。

【问题讨论】:

  • 这是什么 SQL 版本? (另外,请注意,这是您正在尝试的一项非常高级的任务,它并不适合新手)
  • MERGE 和 OUTPUT 很好的解决了这个问题。您可能需要一个 MERGE 语句加上每个表的一个临时表来复制,按照从上到下的拓扑顺序执行。您是否可以一次手动键入所有语句,或者您想要一种在运行时构造 SQL 的基于“反射”的方法?
  • 我想知道@RBarryYoung 在想什么。递归公用表表达式,有人吗?或者这还不足以解决它?
  • @Guttsy 这在很大程度上取决于实际细节。从描述中不清楚这是一个自引用表还是涉及其他表以及它们是如何涉及的。 OP 将需要提供其中一些信息(以表定义和/或关系图的形式)。
  • @usr:我完全可以手动键入每个语句一次,而且我不需要基于反射的方法。

标签: sql sql-server tsql


【解决方案1】:

我假设您要复制表层次结构中的数据子集。我所说的层次结构是指通过外键在这个词的明显意义上相互关联的表。例如,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。

如果我没有把一切都说清楚,请随时提出更多问题。我知道这是一个粗略的草图。

【讨论】:

    【解决方案2】:

    【讨论】:

    • 感谢您的回答。我通读了这篇文章,但仍然难以将其应用于我需要做的事情。如果您需要更多信息,请告诉我。
    • 我经常使用 CTE,我有一个表,它是一个正确的树(没有循环),并且有列:ID、parentID、otherInfo1、otherInfo2、... 在这个结构中很容易编写此类查询: GetAllCildrensOfXRecursive(X) GetAllAncestorsOfXRecursive(X) 上面的函数一直运行到退出条件(例如没有子级)。让我知道您的表格的列、您需要查询的具体内容以及您的表格是否有循环。
    猜你喜欢
    • 2018-01-11
    • 2012-01-27
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 2016-08-31
    相关资源
    最近更新 更多