没有游标的链接表插入

时间:2014-05-08 10:17:01

标签: sql-server tsql sql-server-2005 cursor

TL;博士

使用SQLServer 2005(我们支持的最小值),是否可以在不使用游标的情况下从链接表中复制数据?

详情

我有两张表格,结构粗略......

dbo.[ParentTable]
[ItemId]  [UserId]  [Details]
1         1         'One'
2         1         'Two'

dbo.[ChildTable]
[ChildId]  [ItemId]  [Details]
1          1         'One A'
2          1         'One B'
3          2         'Two A'
4          2         'Two B'

ParentTable.ItemId是具有身份(1,1)的PK ChildTable.ChildId是具有身份(1,1)的PK ChildTable.ItemId是FK到ParentTable.ItemId

目前,如果我需要将UserId=1的所有数据复制到UserId=2,我必须执行以下操作...

DECLARE @ItemId INT, @NewItemId INT

DECLARE [ParentCursor] CURSOR FOR
SELECT [ItemId]
FROM [ParentTable]
WHERE [UserId] = 1

OPEN [ParentCursor]
FETCH NEXT FROM [ParentCursor] INTO @ItemId
WHILE @@FETCH_STATUS = 0
BEGIN
  INSERT INTO [ParentTable] ([UserId], [Details])
  SELECT 2, [Details]
  FROM [ParentTable]
  WHERE [ItemId] = @ItemId

  SET @NewItemId = @@IDENTITY

  INSERT INTO [ChildTable] ([ItemId], [Details]
  SELECT @NewItemId, [Details]
  FROM [ChildTable]
  WHERE [ItemId] = @ItemId

  FETCH NEXT FROM [ParentCursor] INTO @ItemId
END
CLOSE [ParentCursor]
DEALLOCATE [ParentCursor]

这实现了......的预期结果。

dbo.[ParentTable]
[ItemId]  [UserId]  [Details]
1         1         'One'
2         1         'Two'
3         2         'One'
4         2         'Two'

dbo.[ChildTable]
[ChildId]  [ItemId]  [Details]
1          1         'One A'
2          1         'One B'
3          2         'Two A'
4          2         'Two B'
5          3         'One A'
6          3         'One B'
7          4         'Two A'
8          4         'Two B'

有没有一种更简单的方法可以不使用游标?

(注意,我已经尝试创建http://sqlfiddle.com,但我根本无法正确使用游标。与分隔符有关,但我无法弄清楚。)

1 个答案:

答案 0 :(得分:0)

像这样......

declare @olduser int = 1, @newuser int = 2
set transaction isolation level serializable
begin tran

    declare @max int 
    select @max = MAX(itemid) from ParentTable -- as a marker for new records

    -- insert all the parents
    insert ParentTable (userid, details) 
    select @newuser, details from ParentTable where userid=@olduser order by itemid


    insert ChildTable (itemid, details)             
    select newid, details from ChildTable child
        inner join 
    (
            -- join the old parents to the new parents
    select p2.itemid as oldid, p1.itemid as newid   
    from 
        (select *, ROW_NUMBER() over (order by itemid) rn from parenttable where itemid>@max) p1
        inner join 
        (select *, ROW_NUMBER() over (order by itemid) rn from parenttable where userid=@olduser and itemid<=@max) p2
            on p1.rn = p2.rn
    ) oldparents
        on child.itemid = oldparents.oldid
commit tran