scope_identity与ident_current的区别

10

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

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

因此,鉴于这些信息,如果你知道你将要更新哪个表,似乎最好使用ident_current。然而,阅读后,似乎大多数人更喜欢使用scope_identity。这背后的原因是什么,我的逻辑上是否存在缺陷?

6个回答

18
在这种情况下,你需要写入表名,如果你决定更改表名会发生什么?你还必须记得更新你的代码以反映出这一变化。我总是使用 SCOPE_IDENTITY,除非我需要从触发器中发生的插入中获取 ID,那么我将使用 @@IDENTITY。
另外,最大的区别是 IDENT_CURRENT 将为你提供来自执行插入操作的其他进程的标识(换句话说,任何用户上次生成的标识值),因此,如果你进行了一个插入操作,然后有人在你执行 SELECT IDENT_CURRENT 之前进行了插入操作,你将获得该人的标识值。
参见6 Different Ways To Get The Current Identity Value,其中包含了一些代码,说明当你在表上放置触发器时会发生什么。

3

绝对是不使用并行的原因。 - HLGEM
此错误的 KB 文章链接:http://support.microsoft.com/default.aspx?scid=kb;en-US;2019779 - David d C e Freitas

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.*/

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,您可以确保从正确的表中获取正确的标识。

享受吧


0
理论上说:要注意竞态条件,不关心触发器内的插入操作,应该使用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

0

详细答案请参见this博客文章。由于触发器插入的原因,scope_identity永远不会返回标识。在表名被更改的变化世界中使用ident_current并不是一个好主意,比如在开发环境中。


1
不应该使用ident_current来获取刚插入的值,如果你使用它,会导致数据完整性问题,因为它会给出上次插入的标识,即使它不是来自你的连接!如果在数据库中的任何地方使用了这段代码,你就有严重的风险产生错误数据。 - HLGEM
我在哪里说过 ident_current 应该被到处使用了吗? - Perpetualcoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接