【发布时间】:2015-04-17 14:15:23
【问题描述】:
我们有一个表,表示与实体相关联的值树(称为项目),其中 ParentID 列是指行父级的 id 列。 id 列是一个自动递增的 IDENTITY 列和主键。根节点的 ParentID 为 0。
我们希望能够克隆给定项目的数据,并让生成的 ParentID 引用复制值的适当新 id,以符合示例下方描述的限制的方式。
例如,复制下表中 ProjectID 611 的数据:
id ProjectID Value ParentID
--------------------------------------------------
1 611 Animal 0
2 611 Frog 1
13 611 Cow 1
14 611 Jersey Cow 13
25 611 Plant 0
29 611 Tree 25
31 611 Oak 29
应该导致:
id ProjectID Value ParentID
--------------------------------------------------
1 611 Animal 0
2 611 Frog 1
13 611 Cow 1
14 611 Jersey Cow 13
25 611 Plant 0
29 611 Tree 25
31 611 Oak 29
32 612 Animal 0
33 612 Frog 32
34 612 Cow 32
35 612 Jersey Cow 34
36 612 Plant 0
37 612 Tree 36
38 612 Oak 37
限制:
- 解决方案必须适用于 SQL Server 2005。也就是说,我们不能使用 MERGE(唉)。
- 我们不愿意对 ID 或它们与 ParentID 的比较做出假设;例如,该解决方案原则上应适用于唯一 ID 的 ID/ParentID。
- 我们不希望在表格中添加额外的列。 (我当前的解决方案添加了一个“OldId”列,复制过程在复制行时设置该列。所以我目前正在使用 INSERT-SELECT 和 UPDATE-FROM 的组合,加入 ParentID 列上的 OldId 列以获取新 id .) 我们宁愿不要仅仅为了支持这种复制操作而在所有分层表中添加 OldId 列。
- 解决方案必须具有合理的性能;我最初的解决方案是一组复杂的递归函数调用和循环,一次处理一个项目。我很快就放弃了那条路线!
【问题讨论】:
-
CTE 从 SS 2005 开始提供。使用 CTE 和
INSERT上的OUTPUT子句复制树,以获取 id 的修复表(临时或变量),然后应用修复。 -
@HABO 我希望看看我能做到这一点……我听说过 CTE,但不确定如何使用它们来解决这个问题。
-
在考虑使用 CTE 之后,我意识到如果没有
MERGE,它真的无济于事。我添加了一个使用INSERT和一个UPDATE的答案,没有循环,也不需要遍历层次结构。因此,性能应该不会太差。唯一的关键因素是新的层次结构在两个语句之间处于不一致的状态,您需要防止其他用户访问它们,例如使用隔离级别足以满足您的应用程序的事务。
标签: sql sql-server tsql sql-server-2005