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