SQL-克隆记录及其子体

SQL-克隆记录及其子体,sql,sql-server,tsql,sql-server-2008,Sql,Sql Server,Tsql,Sql Server 2008,我希望能够在同一个表中克隆记录及其子体。我的表格示例如下: 表1 id | parentid | name --------------------- 1 | 0 | 'Food' 2 | 1 | 'Taste' 3 | 1 | 'Price' 4 | 2 | 'Taste Requirements' id | parentid | name --------------------- 1 | 0 | '

我希望能够在同一个表中克隆记录及其子体。我的表格示例如下:

表1

id | parentid | name
---------------------
 1 |    0     |  'Food'
 2 |    1     |  'Taste'
 3 |    1     |  'Price'
 4 |    2     |  'Taste Requirements'
id | parentid | name
---------------------
 1 |    0     |  'Food'
 2 |    1     |  'Taste'
 3 |    1     |  'Price'
 4 |    2     |  'Taste Requirements'
 5 |    0     |  'Cookies'
 6 |    5     |  'Taste'
 7 |    5     |  'Price'
 8 |    6     |  'Taste Requirements'
“id”列是主键,自动递增。“食物”记录(即id=1)下面有两个记录,分别称为“味道”和“价格”。“味觉”记录下面有一个名为“味觉要求”的记录。我希望能够克隆“食物”记录,以便表1如下所示:

表1

id | parentid | name
---------------------
 1 |    0     |  'Food'
 2 |    1     |  'Taste'
 3 |    1     |  'Price'
 4 |    2     |  'Taste Requirements'
id | parentid | name
---------------------
 1 |    0     |  'Food'
 2 |    1     |  'Taste'
 3 |    1     |  'Price'
 4 |    2     |  'Taste Requirements'
 5 |    0     |  'Cookies'
 6 |    5     |  'Taste'
 7 |    5     |  'Price'
 8 |    6     |  'Taste Requirements'
(其中“Cookies”是我要创建的新类别的名称)。我可以使用以下方法选择“食物”的所有后代:

with Table1_CTE( id, parentid, name )
as
(
  select t.id, t.parentid, t.name from Table1 t
    where t.id = 1
  union all
  select t.id, t.parentid,t. name from Table1 t
    inner join Table1_CTE as tc
      on t.parentid = tc.id
)
select id, parentid, name from Table1_CTE
我可以使用以下方法克隆“食物”记录(即id=1):


但是我在尝试结合这两个查询来克隆“食物”的后代时遇到了问题。此外,我正在尝试避免使用存储过程、触发器、curosr等。我正在尝试做的是可能的吗?我在网上看到了一些示例,但无法将它们应用到我的要求中。

假设您的CTE选择一个根记录及其所有后代(当我使用上面的数据复制时,似乎没有),那么您可以克隆所有选择的记录并按如下方式插入:

with Table1_CTE( id, parentid, name )
as
(
  select t.id, t.parentid, t.name from Table1 t
    where c.icategoryid = 1
  union all
  select t.id, t.parentid,t. name from Table1
    inner join Table1_CTE as tc
      on t.parentid = tc.id
)
insert into  dbo.testinsertheirarchy  ( parentid, name )  
select  parentid, name from Table1_CTE

正如Martin所建议的,您需要启用
IDENTITY\u INSERT
,以便可以推送您自己的标识值。您可能还需要获取表锁,以确保Max(Id)返回正确的值

If object_id('tempdb..#TestData') is not null
    Drop Table #TestData
GO
Create Table #TestData
    (
    Id int not null identity(1,1) Primary Key
    , ParentId int not null
    , Name varchar(50) not null
    )
GO
Set Identity_Insert #TestData On
GO  
Insert #TestData( Id, ParentId, Name )
Values( 1,0,'Food' )
    , ( 2,1,'Taste' )
    , ( 3,1,'Price' )
    , ( 4,2,'Taste Requirement' );


With Data As
    (
    Select Cast(MaxId.Id + 1 As int) As Id
        , T.ParentId
        , 'Copy Of ' + T.name As Name
        , T.Id As OldId
        , 0 As OldParentId
    From #TestData As T
        Cross Join( Select Max( id ) As Id From #TestData ) As MaxId
    Where T.Name = 'Food'
    Union All
    Select Cast(Parent.id + Row_Number() Over( Order By Child.Id ) + 1 As int)
        , Parent.Id
        , 'Copy of ' + Child.Name
        , Child.Id
        , Child.ParentId
    From Data As Parent
        Join #TestData As Child
            On Child.ParentId = Parent.OldId
    )
Insert #TestData( Id, ParentId, Name )
Select Id, ParentId, Name
From Data
GO
Set Identity_Insert #TestData Off
GO  
结果

id | parentid | name -- | -------- | ----------------- 1 | 0 | Food 2 | 1 | Taste 3 | 1 | Price 4 | 2 | Taste Requirement 5 | 0 | Copy Of Food 7 | 5 | Copy of Taste 8 | 5 | Copy of Price 9 | 7 | Copy of Taste Requirement id | parentid | name -- | -------- | ----------------- 1 | 0 |食物 2 | 1 |味道 3 | 1 |价格 4 | 2 |口味要求 5 | 0 |份食品 7 | 5 |味道副本 8 | 5 |价格副本 9 | 7 |口味要求副本
由于
id
是一个
identity
列,我认为您唯一的选择是在层次结构中执行尽可能多的
insert
操作,并使用
output
子句捕获新插入的
id
s,或者阻止任何并发的插入尝试,自己计算
id
值,然后在启用
identity\u insert
的情况下将其插入到一个操作中。我想知道您是否可以使用插入触发器?如果名称不能保证唯一,您可能会执行插入操作,因为层次结构中有行,除非您使用MERGE,它允许您在集合中插入整个级别,同时记住源和目标之间的链接。您可以阅读更多有关该技术的信息。