Sql 获取插入行标识的最佳方法?

Sql 获取插入行标识的最佳方法?,sql,sql-server,tsql,Sql,Sql Server,Tsql,获取插入行的标识的最佳方法是什么 我知道@@IDENTITY和IDENT_CURRENT和SCOPE_IDENTITY但不了解它们各自的利弊 有人能解释一下它们的区别以及我应该在什么时候使用它们吗?来自MSDN @@IDENTITY、SCOPE_IDENTITY和IDENT_CURRENT是类似的函数,它们返回插入到表的IDENTITY列中的最后一个值 @@IDENTITY和SCOPE_IDENTITY将返回当前会话中任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY仅返回当前范围

获取插入行的
标识
的最佳方法是什么

我知道
@@IDENTITY
IDENT_CURRENT
SCOPE_IDENTITY
但不了解它们各自的利弊

有人能解释一下它们的区别以及我应该在什么时候使用它们吗?

来自MSDN

@@IDENTITY、SCOPE_IDENTITY和IDENT_CURRENT是类似的函数,它们返回插入到表的IDENTITY列中的最后一个值

@@IDENTITY和SCOPE_IDENTITY将返回当前会话中任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY仅返回当前范围内的值@@标识不限于特定的范围

当前标识不受范围和会话的限制;它仅限于指定的表。IDENT_CURRENT返回为任何会话和任何作用域中的特定表生成的标识值。有关更多信息,请参见当前标识

  • IDENT_CURRENT是一个将表作为参数的函数
  • @@当表上有触发器时,IDENTITY可能会返回令人困惑的结果
  • 大多数时候,你的英雄就是你的身份
      • 返回为当前会话中所有作用域中的任何表生成的最后一个标识值这里需要小心,因为它是跨作用域的。您可以从触发器而不是当前语句中获取值

      • 返回为当前会话和当前作用域中的任何表生成的最后一个标识值通常是您想要使用的


      • 返回在任何会话和任何作用域中为特定表生成的最后一个标识值。这允许您指定要从哪个表中获取值,以防上面两个表不是您所需要的(非常罕见)。此外,如@所述,“如果您想获取尚未插入记录的表的当前标识值,可以使用此选项。”

      • INSERT
        语句的属性将允许您访问通过该语句插入的每一行。由于它的作用域是特定的语句,因此它比上面的其他函数更简单。但是,它有一点更详细(您需要插入到表变量/temp表中,然后查询该表),即使在回滚语句的错误场景中,它也会给出结果。也就是说,如果您的查询使用并行执行计划,那么这是获得标识的唯一保证方法(除了关闭并行性)。但是,它在触发器之前执行,不能用于返回触发器生成的值


      @@IDENTITY是使用当前SQL连接插入的最后一个标识。这是从insert存储过程返回的一个很好的值,在该存储过程中,您只需要为新记录插入标识,而不必关心之后是否添加了更多行

      SCOPE\u IDENTITY是使用当前SQL连接插入的最后一个标识,并且在当前范围中——也就是说,如果在插入后根据触发器插入了第二个标识,则它不会反映在SCOPE\u IDENTITY中,只会反映在您执行的插入中。坦白地说,我从来没有理由使用这个


      IDENT_CURRENT(tablename)是插入的最后一个标识,与连接或范围无关。如果您想获取尚未插入记录的表的当前标识值,可以使用此选项。

      我和其他人说的是一样的,所以每个人都是正确的,我只是想说得更清楚一些

      @@IDENTITY
      返回客户端与数据库的连接插入的最后一个内容的id。
      大多数情况下,这很好,但有时触发器会去插入一个您不知道的新行,您将从新行获得ID,而不是您想要的ID

      SCOPE\u IDENTITY()
      解决了这个问题。它返回您在发送到数据库的SQL代码中插入的最后一个内容的id。如果触发器去创建额外的行,它们不会导致返回错误的值。万岁

      IDENT_CURRENT
      返回任何人插入的最后一个ID。如果某个其他应用程序碰巧在不可原谅的时间插入另一行,您将获得该行的ID,而不是您的ID


      如果您想安全起见,请始终使用
      SCOPE\u IDENTITY()
      。如果您坚持使用
      @@IDENTITY
      并且有人决定稍后添加触发器,那么您的所有代码都将中断。

      始终使用scope_IDENTITY(),就不需要其他任何东西了。

      我认为使用output子句是检索插入id的最安全、最准确的方法

      例如(摘自以下文章)

      获取新插入行的标识的最佳(最安全)方法是使用
      output
      子句:

      create table TableWithIdentity
                 ( IdentityColumnName int identity(1, 1) not null primary key,
                   ... )
      
      -- type of this table's column must match the type of the
      -- identity column of the table you'll be inserting into
      declare @IdentityOutput table ( ID int )
      
      insert TableWithIdentity
           ( ... )
      output inserted.IdentityColumnName into @IdentityOutput
      values
           ( ... )
      
      select @IdentityValue = (select ID from @IdentityOutput)
      

      到insert sql语句的末尾,然后

      NewId = command.ExecuteScalar()
      

      将检索它。

      当您使用实体框架时,它在内部使用
      输出
      技术返回新插入的ID值

      DECLARE @generated_keys table([Id] uniqueidentifier)
      
      INSERT INTO TurboEncabulators(StatorSlots)
      OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
      VALUES('Malleable logarithmic casing');
      
      SELECT t.[TurboEncabulatorID ]
      FROM @generated_keys AS g 
         JOIN dbo.TurboEncabulators AS t 
         ON g.Id = t.TurboEncabulatorID 
      WHERE @@ROWCOUNT > 0
      
      输出结果存储在临时表变量中,连接回表,并从表中返回行值

      注意:我不知道为什么EF会将临时表内部连接回实际表(在什么情况下两者不匹配)

      但EF就是这么做的

      此技术(
      输出
      )仅在SQL Server 2008或更高版本上可用

      编辑-加入的原因 实体框架连接回原始表,而不是简单地使用
      输出
      值的原因是,EF还使用此技术获取新插入的
      行版本
      NewId = command.ExecuteScalar()
      
      DECLARE @generated_keys table([Id] uniqueidentifier)
      
      INSERT INTO TurboEncabulators(StatorSlots)
      OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
      VALUES('Malleable logarithmic casing');
      
      SELECT t.[TurboEncabulatorID ]
      FROM @generated_keys AS g 
         JOIN dbo.TurboEncabulators AS t 
         ON g.Id = t.TurboEncabulatorID 
      WHERE @@ROWCOUNT > 0
      
      IDENT_CURRENT('tableName')
      
      INSERT INTO MyTable
      OUTPUT INSERTED.ID
      VALUES (...)
      
      INSERT INTO MyTable
      OUTPUT INSERTED.ID
      VALUES
          (...),
          (...),
          (...)
      
      ID
      2
      3
      4
      
      INSERT INTO table (uuid, name, street, zip) 
              VALUES ('2f802845-447b-4caa-8783-2086a0a8d437', 'Peter', 'Mainstreet 7', '88888');
      
      SELECT * FROM table WHERE uuid='2f802845-447b-4caa-8783-2086a0a8d437';
      
      CREATE TABLE #foo 
        ( 
           fooid   INT IDENTITY NOT NULL, 
           fooname VARCHAR(20) 
        ) 
      
      SELECT @@Identity            AS [@@Identity], 
             Scope_identity()      AS [SCOPE_IDENTITY()], 
             Ident_current('#Foo') AS [IDENT_CURRENT] 
      
      SET IDENTITY_INSERT #foo ON 
      
      INSERT INTO #foo 
                  (fooid, 
                   fooname) 
      VALUES      (1, 
                   'one'), 
                  (2, 
                   'Two') 
      
      SET IDENTITY_INSERT #foo OFF 
      
      SELECT @@Identity            AS [@@Identity], 
             Scope_identity()      AS [SCOPE_IDENTITY()], 
             Ident_current('#Foo') AS [IDENT_CURRENT] 
      
      INSERT INTO #foo 
                  (fooname) 
      VALUES      ('Three') 
      
      SELECT @@Identity            AS [@@Identity], 
             Scope_identity()      AS [SCOPE_IDENTITY()], 
             Ident_current('#Foo') AS [IDENT_CURRENT] 
      
      -- YOU CAN INSERT  
      SET IDENTITY_INSERT #foo ON 
      
      INSERT INTO #foo 
                  (fooid, 
                   fooname) 
      VALUES      (10, 
                   'Ten'), 
                  (11, 
                   'Eleven') 
      
      SET IDENTITY_INSERT #foo OFF 
      
      SELECT @@Identity            AS [@@Identity], 
             Scope_identity()      AS [SCOPE_IDENTITY()], 
             Ident_current('#Foo') AS [IDENT_CURRENT] 
      
      SELECT * 
      FROM   #foo 
      
      CREATE SEQUENCE CountBy1  
          START WITH 1  
          INCREMENT BY 1 ;  
      GO  
      
      SELECT NEXT VALUE FOR CountBy1 AS SequenceID
      GO