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

Lou*_*ers 24 insert output-clause

我正在编写批处理插入语句,并希望使用临时表来跟踪插入的 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
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*her 36

实际上,您可以通过将您的更改INSERTMERGE. 虽然该MERGE语句实际上是在 SQL Server 中执行“更新插入”的一种非常巧妙的方法,但没有什么可以阻止您仅将其用于插入的目的:

-- 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
Run Code Online (Sandbox Code Playgroud)

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

我的代码可能包含错误,因为我还没有实际测试过。几年前的博客文章更详细地介绍了一些细节,包括查询性能。


Dav*_*ett 7

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

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

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

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

-- 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
Run Code Online (Sandbox Code Playgroud)

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

  • 这真是令人失望。这使得输出子句对我的场景毫无用处,除非有第二列可以用作键 :-( 哦,好吧,至少我可以停止尝试并继续循环。谢谢。 (4认同)