我知道这不是您想听到的答案,但答案是使用SCOPE_IDENTITY()
。您正在考虑的问题(将用于何处)any表)是我们使用的原因SCOPE_IDENTITY()
代替@@IDENTITY
。考虑一下这样的情况:你有一张桌子,上面有一个IDENTITY
列,以及该表上的插入触发器,该触发器本身插入到带有IDENTITY
column.
CREATE TABLE dbo.Log(LogID INT IDENTITY(100,1), FooID INT);
CREATE TABLE dbo.Foo(FooID INT IDENTITY(1,1), name VARCHAR(32));
GO
CREATE TRIGGER dbo.Foo_Insert
ON dbo.Foo
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Log(FooID) SELECT FooID FROM inserted;
END
GO
现在,您的情况是您需要一种可靠的方法来在插入后检索 ID。SCOPE_IDENTITY()
给你这个,因为它仅限于你的范围, while @@IDENTITY
不限于您的范围(意味着它将抓住最后一个IDENTITY
已发出,发生在触发器的范围内,而不是您的范围内:
INSERT dbo.Foo(name) SELECT 'Bob';
SELECT
@@IDENTITY,
SCOPE_IDENTITY();
Results:
---- ----
100 1
请注意,两者都不是SCOPE_IDENTITY()
nor @@IDENTITY
应该在插入多行的情况下使用。做到这一点的方法是使用OUTPUT
条款。首先让我们放下触发器:
DROP TRIGGER dbo.Foo_Insert;
现在让我们测试多行插入:
INSERT dbo.Foo(name)
OUTPUT inserted.FooID, inserted.name
SELECT 'Frank' UNION ALL SELECT 'Jim';
Results:
FooID name
----- -----
2 Frank
3 Jim
如果有条件插入,则没有区别。保留我们现有的表,让我们尝试这段代码两次:
DECLARE @table SYSNAME;
SET @table = N'Log';
IF @table = N'Log'
BEGIN
INSERT dbo.Log(FooID) SELECT 10;
END
IF @table = N'Foo'
BEGIN
INSERT dbo.Foo(name) SELECT 'Tom';
END
SELECT SCOPE_IDENTITY();
Result:
----
101
让我们再试一次N'Foo'
:
DECLARE @table SYSNAME;
SET @table = N'Foo';
IF @table = N'Log'
BEGIN
INSERT dbo.Log(FooID) SELECT 10;
END
IF @table = N'Foo'
BEGIN
INSERT dbo.Foo(name) SELECT 'Tom';
END
SELECT SCOPE_IDENTITY();
Results:
----
4
如果它比这更复杂(例如,您可能插入多个表),您可以执行以下操作:
IF <some conditional>
BEGIN
INSERT dbo.sometable ...
SET @somevar = SCOPE_IDENTITY();
END
IF <some other conditional>
BEGIN
INSERT dbo.some_other_table ...
SET @some_other_var = SCOPE_IDENTITY();
END
我不知道为什么你认为这行不通,我也不知道为什么我必须花这么大的篇幅来说服你这行不通。同样,如果您展示了一个不起作用的示例(或者您认为“任何表”可能会干扰),我们也许可以发表评论。就目前情况而言,这听起来像是你的看法SCOPE_IDENTITY()
基于您听说过的事情@@IDENTITY
。这些假设很容易被你自己证明或反驳。
作为旁白,IDENT_CURRENT
甚至不应该在这次谈话中提及。用于并发活动根本不安全,就我而言,您应该假装您从未听说过它。您还应该考虑同样的情况@@IDENTITY
- 我想不出它的有效用途,除非你真的想从触发器外部捕获IDENTITY
在触发器内生成。