经过大量研究后,我对我应该在sql中使用哪个身份跟踪器感到有些困惑。
根据我的理解,scope_identity将为我提供从任何表更新的最后一个id,ident_current将返回指定表中的最后一个id。
所以鉴于这些信息,我觉得最好使用的版本(如果您知道要更新哪个表)是ident_current。然而,在阅读时,似乎大多数人更喜欢使用scope_identity。这背后的原因是什么?我的逻辑是否存在缺陷?
答案 0 :(得分:18)
在这种情况下,您需要编写表名,如果您决定更改表名,会发生什么?您还必须忘记更新代码以反映这一点。除非我需要触发器中插入的ID,否则我总是使用SCOPE_IDENTITY,然后我将使用@@ IDENTITY
另一个更大的区别是IDENT_CURRENT将从另一个执行插入的进程(换句话说,来自任何用户的最后生成的标识值)中提供身份 因此,如果您执行插入操作,然后有人在您执行SELECT IDENT_CURRENT之前执行插入操作,您将获得该其他人的身份值
另请参阅6 Different Ways To Get The Current Identity Value,其中包含一些代码,说明将触发器放在桌面上时会发生什么
答案 1 :(得分:3)
从我所读到的scope_identity()应该是正确的答案,但是看起来SQL 2005和SQL 2008中存在一个错误,如果你的插入导致了并行查询计划。
请查看以下文章了解更多详情:
@@IDENTITY vs SCOPE_IDENTITY() vs IDENT_CURRENT
- Retrieve Last Inserted Identity of Record
文章:Six reasons you should be nervous about parallelism
请参阅标题为: 1的部分。 #328811,“SCOPE_IDENTITY()
有时会返回不正确的值”
答案 2 :(得分:0)
详细了解this blogpost的答案。由于触发器执行的插入,Scope_identity永远不会返回标识。在更改表名的变更世界中使用ident_current并不是一个好主意。就像在dev env中一样。
答案 3 :(得分:0)
/*
* 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.*/
答案 4 :(得分:0)
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,可以确保从右表中获得正确的标识。 享受
答案 5 :(得分:0)
理论上说:要了解竞争条件并且不关心触发器内部的插入,您应该使用SCOPE_IDENTITY()
但是... SCOPE_IDENTITY上存在已知的错误( )(和@@ IDENTITY)如上所述并在其他的anwsers上链接。考虑到这些错误的Here are the workarounds from Microsoft。
以下文章中最相关的部分。它使用output
insert的子句:
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