我知道Scope_Identity()Identity()@@IdentityIdent_Current()都可以获取标识列的值,但我想知道两者之间的区别。

我所遇到的部分争议是它们的意思是

我还喜欢一个使用它们的不同场景的简单示例吗?

评论

不要忘记SQL Server中针对SCOPE_IDENTITY和@@ IDENTITY的并行执行错误:support.microsoft.com/default.aspx?scid=kb;zh-CN;2019779

@DaviddCeFreitas-我很想阅读有关该错误的信息,但是该链接似乎已损坏(或者至少引发了ASP错误)。

实际上,我找到了它:support.microsoft.com/en-us/kb/2019779

修补程序已按照该旧的知识库文章中的说明发布了

#1 楼


@@identity函数返回在同一会话中创建的最后一个身份。
scope_identity()函数返回在同一会话和相同范围内创建的最后一个身份。任何会话中的特定表或视图。
ident_current(name)函数不用于获取身份,而是用于在identity()查询中创建身份。

会话是数据库连接。作用域是当前查询或当前存储过程。

如果表上有触发器,则select...intoscope_identity()函数不同的情况。如果您有插入记录的查询,导致触发器在某处插入另一条记录,则@@identity函数将返回查询创建的标识,而scope_identity()函数将返回触发器创建的标识。

因此,通常您会使用@@identity函数。

评论


我选择了这个作为答案,因为“在这种情况下,scope_identity()和@@ identity ...”段落。它使事情更加清晰。

– Tebo
09年12月17日在10:14

正如上面提到的David Freitas所说,scope_identity的实现存在一个错误,因此我建议使用另一种方法OUTPUT子句。请参阅下面的答案。

–塞巴斯蒂安·梅因(Sebastian Meine)
2012年10月30日在21:15

@Guffa-“会话是数据库连接”。如果使用连接池,会话是否在连接之间维护?

–戴夫·布莱克
16年1月11日在15:19

这是一个榜样的答案。特别是,使用SQL和SQL Server可能很奇怪,这以一种非常清晰,通俗易懂的方式解释了事情,同时仍然提供了很多信息。听起来好像两个数据库专家之间没有交流,很多其他SE答案都可以做到。

–装甲危机
18年2月13日在18:55

@DaveBlack从我读到的内容:不,会话不在池中维护,会话对于connect()之后的脚本运行是唯一的。池化时... SQL Server的PHP使用ODBC连接池。使用池中的连接时,将重置连接状态。关闭连接会将连接返回到池。 (注意:请参阅linux / mac的备注)docs.microsoft.com/zh-cn/sql/connect/php/…

– GDmac
5月5日21:47



#2 楼

很好的问题。


@@IDENTITY:返回在SQL连接(SPID)上生成的最后一个标识值。大多数情况下,它将是您想要的,但有时不是您想要的(例如,当触发触发器以响应INSERT时,触发器执行另一个INSERT语句)。
SCOPE_IDENTITY():返回最后一个标识值在当前作用域(即存储过程,触发器,函数等)中生成。
IDENT_CURRENT():返回特定表的最后一个标识值。不要使用它来获取INSERT的标识值,它受竞争条件的影响(即,多个连接在同一张表上插入行)。
IDENTITY():在表中将一列声明为标识列时使用。

有关更多参考,请参见:http://msdn.microsoft.com/zh-cn/library/ms187342.aspx。

总结:如果要插入行,并且您想知道刚插入的行的标识列的值,请始终使用SCOPE_IDENTITY()

#3 楼

如果您了解范围和会话之间的区别,那么将很容易理解这些方法。
Adam Anderson的一篇非常不错的博客文章描述了这种区别:

Session表示当前的连接执行命令。
作用域表示命令的直接上下文。每个存储过程调用都在其自己的范围内执行,而嵌套调用则在调用过程的范围内的嵌套范围内执行。同样,从应用程序或SSMS执行的SQL命令在其自己的范围内执行,如果该命令触发任何触发器,则每个触发器在其自己的嵌套范围内执行。

因此,这三个身份检索之间的区别方法如下:

@@identity返回在此会话中生成的最后一个标识值,但不包括任何范围。
scope_identity()返回在此会话和此范围中生成的最后一个标识值。
ident_current()返回在任何会话和任何范围中为特定表生成的最后一个标识值。


#4 楼

范围是指执行INSERT语句SCOPE_IDENTITY()的代码上下文,而不是@@IDENTITY的全局范围。

CREATE TABLE Foo(
  ID INT IDENTITY(1,1),
  Dummy VARCHAR(100)
)

CREATE TABLE FooLog(
  ID INT IDENTITY(2,2),
  LogText VARCHAR(100)
)
go
CREATE TRIGGER InsertFoo ON Foo AFTER INSERT AS
BEGIN
  INSERT INTO FooLog (LogText) VALUES ('inserted Foo')
  INSERT INTO FooLog (LogText) SELECT Dummy FROM inserted
END

INSERT INTO Foo (Dummy) VALUES ('x')
SELECT SCOPE_IDENTITY(), @@IDENTITY 


给出不同的结果。

#5 楼

为了弄清楚@@Identity的问题,例如,如果您插入一个表,并且该表具有执行插入操作的触发器,则@@Identity将从触发器中的插入操作返回ID(一个log_id或类似内容),而scope_identity()将返回原始表中插入内容的ID。

因此,如果您没有任何触发器,则scope_identity()@@identity将返回相同的值。如果有触发器,则需要考虑所需的价值。

#6 楼

Scope Identity:正在执行的存储过程中添加的最后一条记录的标识。

@@Identity:查询批处理中添加的最后一条记录的标识,或作为查询结果的结果。一个执行插入操作的过程,然后触发一个触发器,然后插入一条记录,该触发器将返回触发器中插入记录的标识。

IdentCurrent:为表分配的最后一个标识。 >

#7 楼

这是本书中的另一个很好的解释:关于SCOPE_IDENTITY和@@ IDENTITY之间的区别,假设您有一个包含三个语句的存储过程P1:
-An INSERT生成新的标识值
-对存储过程P2的调用,该存储过程还具有INSERT语句,该语句生成新的标识值
-语句查询SCOPE_IDENTITY和@@ IDENTITY函数
SCOPE_IDENTITY函数将返回由P1生成的值(相同的会话和作用域)。 @@ IDENTITY函数将返回P2生成的值(相同的会话,而不管作用域如何)。