Scope_Identity()、Identity()、@@Identity和Ident_Current()之间的区别是什么?

我知道Scope_Identity()Identity()@@Identity,和Ident_Current()都得到单位列的值,但我想知道区别。

我所面临的部分争议是,应用于上述函数的作用域是什么意思?

我还想举一个简单的例子,说明使用它们的不同场景。

190181 次浏览

好问题。

  • @@IDENTITY:返回在SQL连接上生成的最后一个标识值(SPID)。大多数情况下,它会是你想要的,但有时不是(比如当触发器响应INSERT而触发时,触发器执行另一个INSERT语句)。

  • SCOPE_IDENTITY():返回当前作用域中生成的最后一个标识值(即存储过程、触发器、函数等)。

  • IDENT_CURRENT():返回特定表的最后一个标识值。不要使用它来从INSERT中获取标识值,它会受到竞态条件的影响(即多个连接在同一个表中插入行)。

  • IDENTITY():声明表中的列为标识列时使用。

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

总结一下:如果你正在插入行,并且你想知道刚刚插入的行的标识列的值,总是使用SCOPE_IDENTITY()

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

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

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

要澄清@@Identity的问题:

例如,如果你插入一个表,而该表有触发器进行插入,@@Identity将返回触发器中插入的id (log_id或其他),而scope_identity()将返回原始表中插入的id。

因此,如果你没有任何触发器,scope_identity()@@identity将返回相同的值。如果你有触发器,你需要考虑你想要什么值。

  • @@identity函数返回在同一会话中创建的最后一个标识。
  • scope_identity()函数返回在同一会话和同一作用域中创建的最后一个标识。
  • ident_current(name)返回在任何会话中为特定表或视图创建的最后一个标识。
  • identity()函数不用于获取标识,它用于在select...into查询中创建标识。

会话是数据库连接。范围是当前查询或当前存储过程。

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

所以,通常你会使用scope_identity()函数。

作用域是指执行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

给出不同的结果。

如果你理解了作用域和会话之间的区别,那么理解这些方法就很容易了。

Adam Anderson写了一个非常好的博客来描述这种区别:

会话表示正在执行命令的当前连接。

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

因此,三种身份检索方法的区别如下:

@@identity返回在会话中生成的任何作用域的最后一个标识值。

scope_identity()返回在会话和作用域中生成的最后一个标识值。

ident_current()返回在任何会话和任何作用域中为特定表生成的最后一个标识值。

下面是来自这本书的另一个很好的解释:

至于SCOPE_IDENTITY和@@IDENTITY之间的区别,假设您有一个存储过程P1,它有三条语句 —一个INSERT,生成一个新的标识值
—对存储过程P2的调用,该存储过程也有一个INSERT语句,生成一个新的标识值
—查询函数SCOPE_IDENTITY和@@IDENTITY的语句 SCOPE_IDENTITY函数将返回P1生成的值(相同的会话和作用域)。@@IDENTITY函数将返回P2生成的值(不管作用域是相同的会话)