使用SQL克隆数据库中表示的树结构

使用SQL克隆数据库中表示的树结构,sql,sql-server,sql-server-2005,tsql,Sql,Sql Server,Sql Server 2005,Tsql,给定一个表示分层树结构的表,该表有三列 ID主键,不自动递增 父组ID 一些价值 我知道该分支的最低most节点,我想将其复制到一个新分支,该分支的父节点数与需要克隆的父节点数相同 我试图在语句中编写一个SQL INSERT,将同一个main has is part 1 GroupID的每一行复制到一个新的GroupID中 示例开始表: ID | ParentGroupID | SomeValue ------------------------ 1 | -1 |

给定一个表示分层树结构的表,该表有三列

ID主键,不自动递增 父组ID 一些价值 我知道该分支的最低most节点,我想将其复制到一个新分支,该分支的父节点数与需要克隆的父节点数相同

我试图在语句中编写一个SQL INSERT,将同一个main has is part 1 GroupID的每一行复制到一个新的GroupID中

示例开始表:

ID | ParentGroupID | SomeValue
------------------------
1  |      -1       |    a
2  |       1       |    b
3  |       2       |    c
运行简单的INSERT INTO语句后的目标:

ID | ParentGroupID | SomeValue
------------------------
1  |      -1       |    a
2  |       1       |    b
3  |       2       |    c
4  |      -1       |    a-cloned
5  |       4       |    b-cloned
6  |       5       |    c-cloned
最终树结构

+--a (1)
|  +--b (2)
|     +--c (3)
|
+--a-cloned (4)
|  +--b-cloned (5)
|     +--c-cloned (6)
正如这个演示数据所示,ID之间的间隔并不总是很好,因此我不能总是假设父ID比具有父ID的行的当前ID小1

此外,我正在尝试在T-SQL for Microsoft SQL Server 2005及更高版本中实现这一点


这感觉像是一个经典的练习,应该有一个纯SQL的答案,但我太习惯于用关系SQL来编程了。

根据的文章中的查询,尝试一下这个:

在测试数据上运行时的结果:

ID  ParentGroupID  SomeValue  
1   -1             a          
2   1              b          
3   2              c          
4   -1             a-cloned
5   4              b-cloned
6   5              c-cloned

假设该ID是一个标识列,具有自动分配的值。 我是即兴做这件事的,所以对任何语法错误都要道歉。我希望这些评论能清楚地表明意图

/* Find all ancestors for a given ID */
WITH Ancestors(ChildID, AncestorID) AS
(
  SELECT id AS ChildID, id As AncestorID
     FROM YourTable WHERE ParentGroupID=--1
  UNION ALL
  SELECT a.ChildID, d.ParentGroupID
     FROM  Ancestors AS a INNER JOIN
       YourTable d ON d.ID = a.AncestorID
     WHERE (b1.ParentGroupID <> -1))
),
/* Insert new rows for all ancestors of a given ID and save the results, so we have access to the new ID. we also have a column for the old ID. */
IDMap(ID, ParentGroupID, SomeValue, OldID) AS
{
    // insert, using identity column assigned ID, and save the old ID
   INSERT INTO YourTable SELECT d.ParentGroupID, d.SomeValue+"-cloned", d.ID FROM YourTable d
      INNER JOIN Ancestors a ON a.ChildID = d.ID 
      WHERE a.AncestorID=<the ID to clone>
}
/* Now update the parentID in the inserted data to the new ID */
UPDATE YourTable
SET ParentGroupID = map.ID
FROM YouTable t INNER JOIN (SELECT * FROM IDMap) map
  ON t.ParentGroupID=map.OldID

您使用的是哪个版本的SQL Server?我不清楚如何确定克隆的ParentGroupID。B的克隆是如何获得ParentGroupId为4的,而a的克隆获得的ParentGroupId等于其源行的?我需要支持SQL Server 2005。我更新了原来的帖子,指出ID是什么类型的字段-标识列还是手动指定的整数类型?其想法是为新分支保留相同的树结构。当我需要克隆一些与treenode c ID==3关联的数据时,我需要创建一个新节点,然后该节点也具有相同数量的父节点。我把最后的树形结构也添加到了原来的帖子中,因为我可以在评论中使用奇特的格式,我认为我的ID是正确的。。。我只是试着用一个简单的例子来捏造虚拟数据。我要试一下!再次感谢马克!我需要开始关注你们和卡西诺的帖子,因为你们似乎总是有答案!我没有看到任何对@identity的调用,您从哪里获得itI?我同意,我也没有看到。我希望IDMap CTE上有一个OUTPUT子句。也许它被深夜的大脑迷雾吞掉了。我将更新查询。
/* Find all ancestors for a given ID */
WITH Ancestors(ChildID, AncestorID) AS
(
  SELECT id AS ChildID, id As AncestorID
     FROM YourTable WHERE ParentGroupID=--1
  UNION ALL
  SELECT a.ChildID, d.ParentGroupID
     FROM  Ancestors AS a INNER JOIN
       YourTable d ON d.ID = a.AncestorID
     WHERE (b1.ParentGroupID <> -1))
),
/* Insert new rows for all ancestors of a given ID and save the results, so we have access to the new ID. we also have a column for the old ID. */
IDMap(ID, ParentGroupID, SomeValue, OldID) AS
{
    // insert, using identity column assigned ID, and save the old ID
   INSERT INTO YourTable SELECT d.ParentGroupID, d.SomeValue+"-cloned", d.ID FROM YourTable d
      INNER JOIN Ancestors a ON a.ChildID = d.ID 
      WHERE a.AncestorID=<the ID to clone>
}
/* Now update the parentID in the inserted data to the new ID */
UPDATE YourTable
SET ParentGroupID = map.ID
FROM YouTable t INNER JOIN (SELECT * FROM IDMap) map
  ON t.ParentGroupID=map.OldID