在INSERT语句的OUTPUT INTO子句中使用源列(SQL Server)


16

我正在编写一个批处理插入语句,并且想使用一个临时表来跟踪插入的ID,而不是自己遍历项目并为每个插入的行调用SCOPE_IDENTITY()。

需要插入的数据具有(临时)ID将其链接到也应该插入另一个表中的其他数据,因此我需要实际ID和临时ID的交叉引用。

这是到目前为止我所拥有的一个例子:

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

INSERT INTO @MyTable ( [Name] )
   OUTPUT Inserted.ID, INS.ID INTO @MyCrossRef
   SELECT [NAME] FROM @MyInsertData INS

-- Check the result
SELECT * FROM @MyCrossRef

问题是我无法使OUTPUT INTO子句接受ID,我已经尝试过@MyInsertData.ID将表与自身连接起来的其他技巧,但似乎没有任何效果。

Answers:


28

实际上,将更改为可以实现相同INSERT的目的MERGE。虽然该MERGE语句实际上是在SQL Server中执行“ upserts”的一种很整洁的方法,但是没有什么可以阻止您仅出于插入目的而使用它:

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

MERGE INTO @MyTable AS dest
USING @MyInsertData AS ins ON 1=0   -- always false

WHEN NOT MATCHED BY TARGET          -- happens for every row, because 1 is never 0
    THEN INSERT ([Name])
         VALUES (ins.[NAME])

OUTPUT inserted.ID, ins.ID
INTO @MyCrossRef (NewId, OldId);

-- Check the result
SELECT * FROM @MyCrossRef

其中一个好东西大概MERGE是它允许您访问源列以及内置inserteddeleted该表中OUTPUT的条款。

我的代码可能包含错误,因为我尚未进行实际测试。几年前的博客文章更加详细,包括查询性能。


那很棒!这一次,我将不得不坚持循环,因为需要对SQL Server 2005的支持。但是,在以后的项目中,我会牢记这一点。谢谢!
Louis Somers

3
辉煌,这应该是公认的答案。
克里斯·孔雀

3
希望这是在stackoverflow中,而不是dba stackexchange中。它的可见度太小。惊人的答案。
Lordbalmon

3
从一开始就像魅力一样运作...真棒答案!
BeemerGuy19年

5

output子句只能访问目标行和常量/变量中的数据,而不能访问源中其他位置的数据SELECT,就像您在触发器中操作一样。

https://docs.microsoft.com/zh-cn/sql/t-sql/queries/output-clause-transact-sql指出:

对表中要修改的列的任何引用都必须使用INSERTED或DELETED前缀进行限定。

因此,要获取原始ID,您需要将其包括在目标表中,以便output子句可以将其回显,如下所示:

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX), SourceID INT);

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

INSERT INTO @MyTable ( [Name], SourceID )
   OUTPUT Inserted.ID, Inserted.SourceID INTO @MyCrossRef
   SELECT [NAME], ID FROM @MyInsertData INS

-- Check the result
SELECT * FROM @MyCrossRef

尽管在您的情况下更改目标对象的架构可能不切实际,所以这可能不适用。


3
真是令人失望。呈现没用我的情况下输出条款,除非有可以作为一个关键:-(哦,好吧,至少我可以停止尝试,并与循环得到感谢第2列。
路易·萨默斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.