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
8 回答
@@identity
函数返回在同一会话中创建的最后一个标识 .scope_identity()
函数返回在同一会话和相同范围中创建的最后一个标识 .ident_current(name)
返回在任何会话中为特定表或视图创建的最后一个标识 .identity()
函数不用于获取标识,它用于在select...into
查询中创建标识 .会话是数据库连接 . 范围是当前查询或当前存储过程 .
scope_identity()
和@@identity
函数不同的情况是,如果表上有触发器 . 如果您有一个插入记录的查询,导致触发器在某处插入另一条记录,scope_identity()
函数将返回查询创建的标识,而@@identity
函数将返回触发器创建的标识 .所以,通常你会使用
scope_identity()
函数 .好问题 .
@@IDENTITY
:返回SQL连接(SPID)上生成的最后一个标识值 . 大多数情况下它将是您想要的,但有时它不是(就像触发器响应INSERT
时触发,触发器执行另一个INSERT
语句) .SCOPE_IDENTITY()
:返回当前作用域中生成的最后一个标识值(即存储过程,触发器,函数等) .IDENT_CURRENT()
:返回特定表的最后一个标识值 . 不要使用它来从INSERT
获取标识值,它受竞争条件的限制(即在同一个表上插入行的多个连接) .IDENTITY()
:在将表中的列声明为标识列时使用 .有关更多参考,请参阅:http://msdn.microsoft.com/en-us/library/ms187342.aspx .
总结一下:如果要插入行,并且想要知道刚刚插入的行 you 的标识列的值,请始终使用
SCOPE_IDENTITY()
.如果您了解范围和会话之间的区别,那么理解这些方法将非常容易 .
Adam Anderson的一个非常好的blog post描述了这种差异:
因此,三种身份检索方法之间的差异如下:
Scope表示执行
INSERT
语句SCOPE_IDENTITY()
的代码上下文,而不是@@IDENTITY
的全局范围 .给出不同的结果 .
由于@David Freitas提到的错误,并且由于与2012年引入的新序列功能不兼容,我建议远离所有这三个 . 相反,您可以使用OUTPUT子句来获取插入的标识值 . 另一个优点是,如果您插入了多行,OUTPUT甚至可以工作 .
有关详细信息和示例,请参见此处:Identity Crisis
要澄清
@@Identity
的问题:例如,如果您插入一个表并且该表具有执行插入的触发器,
@@Identity
将从触发器中的插入返回id(log_id
或其他),而scope_identity()
将从原始表中的插入返回id .因此,如果您没有任何触发器,
scope_identity()
和@@identity
将返回相同的值 . 如果你有触发器,你需要考虑你想要的 Value .以下是the book的另一个很好的解释:
Scope Identity
:最后一条记录的身份在正在执行的存储过程中添加 .@@Identity
:查询批次中添加的最后一条记录的标识,或者作为查询结果的标识,例如执行插入的过程然后触发一个触发器,然后插入一个记录将从触发器返回插入记录的标识 .IdentCurrent
:为表分配的最后一个标识 .