SQL Server - INSERT后的返回值

mel*_*bic 279 sql sql-server sql-server-2008

我试图在INSERT声明后得到一个键值.示例:我有一个包含属性name和id的表.id是生成的值.

    INSERT INTO table (name) VALUES('bob');
Run Code Online (Sandbox Code Playgroud)

现在我想在同一步骤中恢复身份.这是怎么做到的?

我们正在使用Microsoft SQL Server 2008.

gbn*_*gbn 441

无需单独的SELECT ...

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');
Run Code Online (Sandbox Code Playgroud)

这适用于非IDENTITY列(例如GUID)

  • 你能详细说一下吗?输出在这个例子中的位置是什么?[文档](http://technet.microsoft.com/en-us/library/ms177564.aspx)仅显示表的示例(使用output ... into).理想情况下,我希望能够将其传递给变量 (26认同)
  • 不幸的是,你不能依赖于此,因为在表中添加触发器会破坏你的陈述!re:http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx (7认同)
  • 切勿使用@@ IDENTITY.SCOPE_IDENTITY,是的,但绝不是@@ IDENTITY.这是不可靠的 (4认同)
  • @JonnyLeeds:你不能把它做成一个变量(除非是一个表变量).OUTPUT转到客户端或表 (2认同)
  • @hajikelist:这是一种非常边缘的情况,在触发器中设置 NCOOUNT ON 通常会有所帮助。请参阅http://stackoverflow.com/questions/1483732/set-nocount-on-usage (2认同)

Cur*_*urt 175

使用SCOPE_IDENTITY()以获取新的ID值

INSERT INTO table (name) VALUES('bob');

SELECT SCOPE_IDENTITY()
Run Code Online (Sandbox Code Playgroud)

http://msdn.microsoft.com/en-us/library/ms190315.aspx

  • @ liho1eye - OP将标识列名称称为"id",所以是的. (11认同)
  • 假设`id`是身份 (6认同)
  • @Shiv "SCOPE_IDENTITY 返回仅在当前范围内插入的值" (5认同)
  • 在较大的系统上,如果同时运行多个sql怎么办?它将为每个请求返回最后插入的ID吗? (2认同)

haj*_*ist 42

INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();
Run Code Online (Sandbox Code Playgroud)

是最安全的赌注,因为在带触发器的表上存在OUTPUT子句冲突的已知问题.这使得这非常不可靠,即使您的表当前没有任何触发器 - 有人在线下添加一个会破坏您的应用程序.时间炸弹的行为.

有关更深入的解释,请参阅msdn文章

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx

  • 仅当您不在触发器中添加 SET NOCOUNT ON 时。另请参阅 https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/disallow-results-from-triggers-server-configuration-option (2认同)
  • @gbn - 我只是想避免这样的愚蠢事情。我不会告诉我所有的开发人员,“不要忘记在每个触发器中添加‘不要破坏我的应用程序声明’。” - 你可以留着。在我看来,“相反”的情况更像是一种边缘情况。 (2认同)

Ian*_*oyd 26

实体框架执行类似于gbn的答案:

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO @generated_keys
VALUES('bob');

SELECT t.[CustomerID]
FROM @generated_keys AS g 
   JOIN dbo.Customers AS t 
   ON g.Id = t.CustomerID
WHERE @@ROWCOUNT > 0
Run Code Online (Sandbox Code Playgroud)

输出结果存储在临时表变量中,然后选择回客户端.必须要知道这个问题:

insert可以生成多行,因此变量可以包含多行,因此可以返回多行 ID

我不知道为什么EF会将短暂的表连接回真实表(在什么情况下两者不匹配).

但这就是EF所做的.

SQL Server 2008或更新版本.如果它是2005年,那么你运气不好.

  • EF 这样做的原因是确保它也可以“看到”对插入的“Customer”记录的所有其他更改,因为可能有其他数据库端逻辑影响它,例如某些列上的“DEFAULT”、表上的触发器EF 更新用于插入的实体(对象),因此客户端获取带有 ID 的客户对象以及代表该行当前状态的所有其他内容。 (2认同)

Rez*_*abi 17

插入后退出的方式有很多种

向表中插入数据时,可以使用 OUTPUT 子句返回已插入表中的数据的副本。OUTPUT 子句采用两种基本形式:OUTPUT 和 OUTPUT INTO。如果要将数据返回到调用应用程序,请使用 OUTPUT 表单。如果要将数据返回到表或表变量,请使用 OUTPUT INTO 表单。

DECLARE @MyTableVar TABLE (id INT,NAME NVARCHAR(50));

INSERT INTO tableName
(
  NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO @MyTableVar
VALUES
(
   'test',...
)
Run Code Online (Sandbox Code Playgroud)

IDENT_CURRENT:它返回为任何会话中的特定表或视图创建的最后一个标识。

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]
Run Code Online (Sandbox Code Playgroud)

SCOPE_IDENTITY:它返回来自同一会话和同一范围的最后一个身份。范围是存储过程/触发器等。

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  
Run Code Online (Sandbox Code Playgroud)

@@IDENTITY:它返回同一会话的最后一个身份。

SELECT @@IDENTITY AS [@@IDENTITY];
Run Code Online (Sandbox Code Playgroud)

  • @RezaJenabi Jun,**输出**工作得很好,比在表中查找许多 id 更好。我使用“out put”作为“bulk insert”,并通过“select statements”插入。谢谢你的建议 (2认同)

Ang*_*laG 9

@@ IDENTITY是一个返回最后插入的标识值的系统函数.

  • 不得不建议不要使用@@ IDENTITY - 它不准确(太宽泛)而不是线程安全 - 请参阅@ Curt关于SCOPE_IDENTITY()的回答. (4认同)

小智 6

有多种方法可以在插入命令后获取最后插入的 ID。

  1. @@IDENTITY :它返回在当前会话中的连接上生成的最后一个标识值,而不管表和产生该值的语句的范围
  2. SCOPE_IDENTITY(): 返回当前连接中当前作用域中insert语句生成的最后一个标识值,不考虑表。
  3. IDENT_CURRENT(‘TABLENAME’):无论任何连接、会话或范围如何,它都会返回在指定表上生成的最后一个标识值。IDENT_CURRENT 不受范围和会话的限制;它仅限于指定的表。

现在似乎更难决定哪一个将完全符合我的要求。

我最喜欢 SCOPE_IDENTITY()。

如果您在插入语句中使用 select SCOPE_IDENTITY() 和 TableName,您将获得符合您期望的确切结果。

来源:CodoBee


MNF*_*MNF 5

最好和最确定的解决方案是使用SCOPE_IDENTITY().

只是您必须在每次插入后获取范围标识并将其保存在变量中,因为您可以在同一范围内调用两次插入。

ident_current并且@@identity可能它们有效,但它们不是安全范围。您可能会在大型应用程序中遇到问题

  declare @duplicataId int
  select @duplicataId =   (SELECT SCOPE_IDENTITY())
Run Code Online (Sandbox Code Playgroud)

更多细节在这里Microsoft docs

  • 可以简化为```select @duplicataId = SCOPE_IDENTITY()``` (2认同)