【问题标题】:@@IDENTITY, SCOPE_IDENTITY(), OUTPUT and other methods of retrieving last identity@@IDENTITY、SCOPE_IDENTITY()、OUTPUT 和其他检索最后身份的方法
【发布时间】:2009-01-26 21:19:38
【问题描述】:

我见过在插入后检索主键标识字段的值时使用的各种方法。

declare @t table (
    id int identity primary key,
    somecol datetime default getdate()
)
insert into @t
default values

select SCOPE_IDENTITY() --returns 1
select @@IDENTITY --returns 1

在插入后返回一个身份表:

Create Table #Testing (  
    id int identity,  
    somedate datetime default getdate()  
)  
insert into #Testing  
output inserted.*  
default values   

什么方法合适或更好? OUTPUT 方法范围安全吗?

第二个代码sn-p是从SQL in the Wild借来的

【问题讨论】:

    标签: sql sql-server tsql identity output-clause


    【解决方案1】:

    这取决于你想要做什么......

    @@IDENTITY

    返回在连接上生成的最后一个 IDENTITY 值,与生成该值的表无关,也与生成该值的语句的范围无关。 @@IDENTITY 将返回在当前会话中输入到表中的最后一个标识值。 @@IDENTITY 仅限于当前会话,不限于当前范围。例如,如果您在一个表上有一个触发器导致在另一个表中创建一个身份,您将获得最后创建的身份,即使它是创建它的触发器。

    SCOPE_IDENTITY()

    返回由连接和同一范围内的语句生成的最后一个 IDENTITY 值,而与生成该值的表无关。 SCOPE_IDENTITY() 类似于@@IDENTITY,但它也会将值限制在您当前的范围内。换句话说,它将返回您显式创建的最后一个标识值,而不是由触发器或用户定义的函数创建的任何标识。

    IDENT_CURRENT()

    返回表中生成的最后一个 IDENTITY 值,与生成该值的语句的连接和范围无关。 IDENT_CURRENT 仅限于指定的表,但不受连接或范围的限制。

    【讨论】:

    • 您没有描述使用 OUTPUT,这是 SQL Server 较新版本中的首选方法。它不仅是范围安全的,而且如果您需要它们进行未来处理,它可以返回多个身份甚至其他字段。
    • @HLGEM,OUTPUT 很好,但是当您只需要一个标识值时使用起来有点尴尬。
    • @Constantin,虽然这是真的,但这是微软获得价值的首选方式,从我读过的东西来看,他们无意在未来解决 @@identity 和 scope_Identity 的任何问题因为他们认为 OUTPUT 是替代品。
    • @HLGEM 哪里说@@identity会被OUTPUT代替?
    • @Domcha:是的,它会告诉你,当你有一个插入触发器时尝试运行输出。
    【解决方案2】:

    请注意,scope_identity()@@identity 中存在错误 - 请参阅 MS Connect:https://web.archive.org/web/20130412223343/https://connect.microsoft.com/SQLServer/feedback/details/328811/scope-identity-sometimes-returns-incorrect-value

    引用(来自微软):

    我强烈建议在所有情况下都使用OUTPUT 而不是@@IDENTITY。 这只是读取身份和时间戳的最佳方式。

    编辑添加:现在可能已修复。 Connect 给了我一个错误,但请参阅:

    Scope_Identity() returning incorrect value fixed?

    【讨论】:

    • 我只想提一下,使用并行时会出现上述错误。但这不会影响执行单个插入的情况。这是来自微软的报价。 “每当生成并行查询计划时,@@IDENTITY 和 SCOPE_IDENTITY() 都不会一致地更新,不能依赖。”
    • SCOPE_IDENTITY() 怎么样?似乎@@IDENTITY 在更多用例中一直存在问题。
    【解决方案3】:

    在尝试获取刚刚插入的行的标识时,几乎没有理由使用除 OUTPUT 子句之外的任何内容。 OUTPUT 子句是范围和表安全的。

    这是一个插入单行后获取id的简单示例...

    DECLARE @Inserted AS TABLE (MyTableId INT);
    
    INSERT [MyTable] (MyTableColOne, MyTableColTwo)
    OUTPUT Inserted.MyTableId INTO @Inserted
    VALUES ('Val1','Val2')
    
    SELECT MyTableId FROM @Inserted
    

    OUTPUT 子句的详细文档:http://technet.microsoft.com/en-us/library/ms177564.aspx


    -- table structure for example:     
    CREATE TABLE MyTable (
        MyTableId int NOT NULL IDENTITY (1, 1),
        MyTableColOne varchar(50) NOT NULL,
        MyTableColTwo varchar(50) NOT NULL
    )
    

    【讨论】:

    • 注意:在游标中使用这种类型的东西时,请务必在每次迭代中从表变量中删除所有内容,因为 DECLARE 不会重新初始化。
    【解决方案4】:

    @@Identity 是老派的方式。在以后的所有实例中使用 SCOPE_IDENTITY()。请参阅 MSDN 了解使用 @@IDENTITY 的影响(它们很糟糕!)。

    【讨论】:

    • 即使是 SCOPE_IDENTITY() 在执行自己的 INSERT 的触发器方面也存在问题。 (为您提供任何触发器插入的最后一个表的标识)
    • 该链接中的示例代码似乎与您的陈述相矛盾。很确定触发器发生在不同的范围内。
    • @Dems,这完全不是真的
    • 哇,对两年前发表的评论的回应......是的,在我添加该评论的那天,我似乎要么喝醉了,要么只是非常愚蠢。
    【解决方案5】:

    SCOPE_IDENTITY 对于单行就足够了,建议您使用,除非您出于某种原因需要查看中间 TRIGGER 的结果(为什么?)。

    对于多行,OUTPUT/OUTPUT INTO 是您最好的新朋友,也是重新查找行并插入另一个表的替代方法。

    【讨论】:

      【解决方案6】:

      SQL Server 2005 中还有另一种可用的方法,概述为in SQL in the Wild

      这将允许您在插入后检索多个身份。以下是博文中的代码:

      Create Table #Testing (  
          id int identity,  
          somedate datetime default getdate()  
      )  
      insert into #Testing  
      output inserted.*  
      default values
      

      【讨论】:

      • 我以前见过这个,但认为它不是范围安全的。这意味着我可能会看到其他人的插入。不知道是不是真的。
      • 我不确定。我会将这个添加到问题中。
      • 输出是范围安全的。从现在开始,这是首选方法。
      【解决方案7】:

      对 Godeke 的回答的一个小修正:

      您需要担心的不仅仅是触发器。任何导致创建标识符的嵌套操作(例如存储过程)都可能更改 @@IDENTITY 的值。

      再次为 scope_identity 投票...

      【讨论】:

        【解决方案8】:
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-26
        • 2013-08-18
        相关资源
        最近更新 更多