SQL Server:是否可以在没有表变量的情况下获取最近插入的标识列值

a1e*_*x07 1 sql-server

假设我有一张桌子

my_table(id int identity(1,1) not null primary key, data varchar(100))
Run Code Online (Sandbox Code Playgroud)

我想编写一个过程,在该表中插入一个新行并返回id.我试过了

DECLARE @new_id INT;    
SELECT @new_id = id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test') 
) as NewVal(id)
Run Code Online (Sandbox Code Playgroud)

该代码不起作用(我得到"在INSERT语句的行的直接来源的SELECT语句中不允许嵌套的INSERT,UPDATE,DELETE或MERGE语句.").但是,如果我使用表变量,我可以这样做

DECLARE @new_id INT;    
DECLARE @tmp_table TABLE(int id);
INSERT INTO @tmp_table
SELECT id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')  
) as NewVal(id);
// OR 
INSERT INTO my_table(data) OUTPUT inserted.id INTO @tmp_table VALUES ('test') ;
SELECT @new_id = id FROM @tmp_table;
Run Code Online (Sandbox Code Playgroud)

是否可以在不使用表变量的情况下实现相同的功能?

更新
感谢您的快速回复,为每个人提供+1 SCOPE_IDENTITY解决方案.这可能是我的错,我应该清楚地问过这个问题 - 我确实使用过MERGE(一个例子会更长,所以我发布了INSERT),不是INSERT这样,SCOPE_IDENTITY并不适合我.

Ada*_*Dev 5

是的,您可以在插入后返回SCOPE_IDENTITY(由于范围不同,这比@@ IDENTITY更安全).

INSERT my_table (data) VALUES ('test')
SELECT SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)


Mik*_*son 5

比使用insert语句中的嵌套更短的版本output...into.

declare @tmp_table table(actiontaken nvarchar(10), id int);

merge my_table
using (values ('test')) as S(data)
on 0=1
when not matched then 
  insert (data) values (S.data)
output $action, inserted.id into @tmp_table;
Run Code Online (Sandbox Code Playgroud)

我相信你应该使用合并中的表变量.输出可能包含多行.