Sql server 使用SQL Server 2005中的输出将表行复制到

Sql server 使用SQL Server 2005中的输出将表行复制到,sql-server,performance,sql-server-2005,insert,output-clause,Sql Server,Performance,Sql Server 2005,Insert,Output Clause,我有一个表,我需要将记录从表中复制回表本身。作为其中的一部分,我希望使用OUTPUT子句将新行捕获到表变量中,这样我就可以在同一过程中对这些行执行其他操作。我希望每一行都包含它的新键和它从中复制的键。下面是一个人为的例子: INSERT MyTable (myText1, myText2) -- myId is an IDENTITY column OUTPUT Inserted.myId, Inserted.myText1, Inserted.myTe

我有一个表,我需要将记录从表中复制回表本身。作为其中的一部分,我希望使用OUTPUT子句将新行捕获到表变量中,这样我就可以在同一过程中对这些行执行其他操作。我希望每一行都包含它的新键和它从中复制的键。下面是一个人为的例子:

INSERT 
    MyTable (myText1, myText2) -- myId is an IDENTITY column
OUTPUT  
    Inserted.myId, 
    Inserted.myText1, 
    Inserted.myText2 
INTO
    -- How do I get previousId into this table variable AND the newly inserted ID? 
    @MyTable    
SELECT 
    -- MyTable.myId AS previousId,
    MyTable.myText1,
    MyTable.myText2
FROM
    MyTable
WHERE
    ...
如果INSERT上的列数与SELECT语句中的列数不匹配,SQL Server将发出吠声。因此,如果我在MyTable中添加了一列,我可以看到这是如何工作的,但这不是一个选项。以前,这是用一个游标实现的,它会导致性能瓶颈——我有意避免这种情况


如何在复制这些记录的同时保留复制行的键,以实现尽可能高的性能?

我对上下文有点不清楚-这是在插入后触发器中进行的

不管怎样,我看不出任何方法可以在一个电话里做到这一点。OUTPUT子句只允许返回插入的行。我的建议如下:

DECLARE @MyTable (
    myID INT, 
    previousID INT, 
    myText1 VARCHAR(20), 
    myText2 VARCHAR(20)
)

INSERT @MyTable (previousID, myText1, myText2) 
SELECT myID, myText1, myText2 FROM inserted

INSERT MyTable (myText1, myText2) 
SELECT myText1, myText2 FROM inserted

-- @@IDENTITY now points to the last identity value inserted, so...
UPDATE m SET myID = i.newID
FROM @myTable m, (SELECT @@IDENTITY - ROW_NUMBER() OVER(ORDER BY myID DESC) + 1 AS newID, myID FROM inserted) i
WHERE m.previousID = i.myID

...

当然,您不会将其放入AFTER INSERT触发器中,因为它会给您一个递归调用,但您可以在INSTEAD Of INSERT触发器中执行。我可能在递归问题上错了;我总是避免递归调用,所以我从未真正发现。然而,使用@@IDENTITY和ROW_NUMBER()是我过去多次使用的一个技巧来做类似的事情。

我对上下文有点不清楚-这是在插入后触发器中

不管怎样,我看不出任何方法可以在一个电话里做到这一点。OUTPUT子句只允许返回插入的行。我的建议如下:

DECLARE @MyTable (
    myID INT, 
    previousID INT, 
    myText1 VARCHAR(20), 
    myText2 VARCHAR(20)
)

INSERT @MyTable (previousID, myText1, myText2) 
SELECT myID, myText1, myText2 FROM inserted

INSERT MyTable (myText1, myText2) 
SELECT myText1, myText2 FROM inserted

-- @@IDENTITY now points to the last identity value inserted, so...
UPDATE m SET myID = i.newID
FROM @myTable m, (SELECT @@IDENTITY - ROW_NUMBER() OVER(ORDER BY myID DESC) + 1 AS newID, myID FROM inserted) i
WHERE m.previousID = i.myID

...

当然,您不会将其放入AFTER INSERT触发器中,因为它会给您一个递归调用,但您可以在INSTEAD Of INSERT触发器中执行。我可能在递归问题上错了;我总是避免递归调用,所以我从未真正发现。但是,使用@@IDENTITY和ROW_NUMBER()是我过去多次使用的一个技巧,用于做类似的事情。

正如您所提到的,最简单的方法是增加一列以容纳旧ID。为什么添加列不是一个选项?是的,我想您是对的,但是这个列在这个复制操作之外是没有意义的——我想如果没有其他结果的话,我并不完全反对它。正如你所说,它并不理想,因为它实际上不是数据的一部分。我想您可以将列添加为过程的一部分,然后将其删除,但这似乎有点繁琐。我会尝试将其设置为可空,并确保在使用后清空列以节省空间(假设不需要在过程之外保留旧的ID值),如果您使用的是SQL Server 2008,则可以使用
合并
@Mikael Eriksson是的,我希望能够使用合并。正如你所提到的,最简单的方法是增加一个列来容纳旧ID。为什么不选择添加列?是的,我认为你是对的,但是这个列在这个复制操作之外是没有意义的——我想如果没有其他结果的话,我并不完全反对它。正如你所说,它并不理想,因为它实际上不是数据的一部分。我想您可以将列添加为过程的一部分,然后将其删除,但这似乎有点繁琐。我会尝试将其设置为可空,并确保在使用后清空列以节省空间(假设不需要在过程之外保留旧的ID值),如果您使用的是SQL Server 2008,则可以使用
合并
@米凯尔·埃里克森是的,我希望能够使用合并。我不认为这是一个触发器。我相信这只是一个普通的SP。我不认为这是一个触发器。我相信这只是一个普通的SP。