经过大量研究,我对应该在sql中使用哪个身份标识跟踪器感到有些困惑。
据我了解,scope_identity将为我提供从任何表更新的最后一个id,而ident_current将返回指定表中的最后一个id。
因此,鉴于这些信息,如果你知道你将要更新哪个表,似乎最好使用ident_current。然而,阅读后,似乎大多数人更喜欢使用scope_identity。这背后的原因是什么,我的逻辑上是否存在缺陷?
经过大量研究,我对应该在sql中使用哪个身份标识跟踪器感到有些困惑。
据我了解,scope_identity将为我提供从任何表更新的最后一个id,而ident_current将返回指定表中的最后一个id。
因此,鉴于这些信息,如果你知道你将要更新哪个表,似乎最好使用ident_current。然而,阅读后,似乎大多数人更喜欢使用scope_identity。这背后的原因是什么,我的逻辑上是否存在缺陷?
根据我所读的,应该使用 scope_identity() 来获得正确答案,然而如果插入操作导致并行查询计划,则在 SQL 2005 和 SQL 2008 中可能会出现错误。
请查看以下文章以获取更多详细信息:
@@IDENTITY vs SCOPE_IDENTITY() vs IDENT_CURRENT
- 检索最后插入记录的标识符
请参见标题为:1. #328811, "SCOPE_IDENTITY()
有时返回不正确的值" 的部分。
/*
* IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
* @@IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
* SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.
*/
IF OBJECT_ID(N't6', N'U') IS NOT NULL
DROP TABLE t6 ;
GO
IF OBJECT_ID(N't7', N'U') IS NOT NULL
DROP TABLE t7 ;
GO
CREATE TABLE t6 (id INT IDENTITY) ;
CREATE TABLE t7
(
id INT IDENTITY(100, 1)
) ;
GO
CREATE TRIGGER t6ins ON t6
FOR INSERT
AS
BEGIN
INSERT t7
DEFAULT VALUES
END ;
GO
--End of trigger definition
SELECT id
FROM t6 ;
--IDs empty.
SELECT id
FROM t7 ;
--ID is empty.
--Do the following in Session 1
INSERT t6
DEFAULT VALUES ;
SELECT @@IDENTITY ;
/*Returns the value 100. This was inserted by the trigger.*/
SELECT SCOPE_IDENTITY() ;
/* Returns the value 1. This was inserted by the
INSERT statement two statements before this query.*/
SELECT IDENT_CURRENT('t7') ;
/* Returns 100, the value inserted into t7, that is in the trigger.*/
SELECT IDENT_CURRENT('t6') ;
/* Returns 1, the value inserted into t6 four statements before this query.*/
-- Do the following in Session 2.
SELECT @@IDENTITY ;
/* Returns NULL because there has been no INSERT action
up to this point in this session.*/
SELECT SCOPE_IDENTITY() ;
/* Returns NULL because there has been no INSERT action
up to this point in this scope in this session.*/
SELECT IDENT_CURRENT('t7') ;
/* Returns 100, the last value inserted into t7.*/
SELECT IDENT_CURRENT
-- 正如你所说,将给出特定表的最后插入的标识值。这种方法存在一些问题,首先用户需要有权限查看元数据,否则会返回NULL;其次,你硬编码了表名,如果表名发生变化,就会导致问题。
最佳实践是使用Scope_Identity和一个变量...请看下面的示例:
DECLARE @myFirstTableID INT
DECLARE @mySecondTableID INT
INSERT INTO MYFirstTable (....) VALUES (.....)
SELECT @myFirstTableID =SCOPE_IDENTITY()
INSERT INTO MYSecondTable () VALUES (.....)
SELECT @mySecondTableID=SCOPE_IDENTITY()
因此,通过在感兴趣的插入语句旁边使用变量和scope_identity,您可以确保从正确的表中获取正确的标识。
享受吧
SCOPE_IDENTITY()
但是...已知 SCOPE_IDENTITY()(和 @@IDENTITY)存在错误,如其他答案中所述并链接。这里是微软提供的解决方法,考虑到这些错误。
以下是文章中最相关的部分。它使用了 output
插入子句:
DECLARE @MyNewIdentityValues table(myidvalues int)
declare @A table (ID int primary key)
insert into @A values (1)
declare @B table (ID int primary key identity(1,1), B int not null)
insert into @B values (1)
select
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
set statistics profile on
insert into _ddr_T
output inserted.ID into @MyNewIdentityValues
select
b.ID
from @A a
left join @B b on b.ID = 1
left join @B b2 on b2.B = -1
left join _ddr_T t on t.T = -1
where not exists (select * from _ddr_T t2 where t2.ID = -1)
set statistics profile off
select
[RowCount] = @@RowCount,
[@@IDENTITY] = @@IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY(),
[IDENT_CURRENT] = IDENT_CURRENT('_ddr_T')
select * from @MyNewIdentityValues
go
详细答案请参见this博客文章。由于触发器插入的原因,scope_identity永远不会返回标识。在表名被更改的变化世界中使用ident_current并不是一个好主意,比如在开发环境中。