scope_identity vs ident_current

时间:2009-02-19 21:08:30

标签: sql sql-server tsql

经过大量研究后,我对我应该在sql中使用哪个身份跟踪器感到有些困惑。

根据我的理解,scope_identity将为我提供从任何表更新的最后一个id,ident_current将返回指定表中的最后一个id。

所以鉴于这些信息,我觉得最好使用的版本(如果您知道要更新哪个表)是ident_current。然而,在阅读时,似乎大多数人更喜欢使用scope_identity。这背后的原因是什么?我的逻辑是否存在缺陷?

6 个答案:

答案 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