提问



得到IDENTITY插入行的最佳方法是什么?


我知道@@IDENTITYIDENT_CURRENTSCOPE_IDENTITY,但不了解每个人的利弊。


有人可以解释一下这些差异,以及何时我应该使用它们?

最佳参考



  • @@IDENTITY返回在所有范围内为当前会话中的任何表生成的最后一个标识值。 你需要在这里小心,因为它跨越了范围。你可以从触发器获得一个值,而不是你当前的声明。[27]

  • SCOPE_IDENTITY()返回为当前会话中的任何表和当前范围生成的最后一个标识值。 一般您想要使用[28]

  • IDENT_CURRENT('tableName')返回在任何会话和任何范围内为特定表生成的最后一个标识值。这可以让你指定你想要这个值的表,如果上面的两个不是你需要的(非常罕见)。另外,正如@Guy Starbuck所说,你可以使用这个你想得到你没有插入记录的表的当前IDENTITY值。[29]

  • INSERT语句的OUTPUT子句将允许您访问通过该语句插入的每一行。由于它的范围是特定的声明,它比上面的其他函数更强大 。但是,它有点更详细(您需要插入表变量/临时表然后进行查询),即使在回滚语句的错误情况下,它也会给出结果。也就是说,如果您的查询使用并行执行计划,这是获取身份的唯一保证的方法(缺少关闭并行性)。但是,它在触发之前执行,不能用于返回触发器生成的值。[31]


其它参考1


我相信检索插入的id的最安全和最准确的方法是使用output子句。


例如(取自以下MSDN文章)[32]


USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
                           Name varchar(50),
                           ModifiedDate datetime);
INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate 
FROM Production.ScrapReason;
GO

其它参考2


我说的和其他人一样,所以每个人都是对的,我只是想让它更清楚。


@@IDENTITY返回客户端与数据库连接所插入的最后一个内容的id
大部分时间这种方法都可以正常工作,但有时触发器会插入一个你不知道的新行,你将从这个新行中获取ID,而不是你想要的那个


SCOPE_IDENTITY()解决了这个问题。它将您发送的 > 中插入的最后一个内容的id返回给数据库。如果触发器去创建额外的行,他们就不会导致返回错误的值。万岁


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


如果您想安全使用,请务必使用SCOPE_IDENTITY()。如果您坚持使用@@IDENTITY并且某人决定稍后添加触发器,则所有代码都将中断。

其它参考3


获取新插入行的标识的最佳(读取:最安全)方法是使用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)

其它参考4





SELECT CAST(scope_identity() AS int);


到插入sql语句的末尾,然后


NewId = command.ExecuteScalar()


将检索它。

其它参考5


MSDN [33]



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

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

  
  IDENT_CURRENT不受范围和会话的限制;它仅限于指定的表格。 IDENT_CURRENT返回在任何会话和任何范围内为特定表生成的标识值。有关更多信息,请参阅IDENT_CURRENT。




  • IDENT_CURRENT是一个以表格为参数的函数。

  • @@ IDENTITY可能会在表格中触发时返回令人困惑的结果

  • SCOPE_IDENTITY大部分时间都是你的英雄。


其它参考6


@@ IDENTITY 是使用当前SQL Connection插入的最后一个标识。这是从插入存储过程返回的一个很好的值,您只需要为新记录插入标识,并且不关心以后是否添加了更多行。[34] [35] [36]


SCOPE_IDENTITY 是使用当前SQL连接插入的最后一个标识,并且在当前范围内 - 也就是说,如果在插入后基于触发器插入了第二个IDENTITY,则不会反映在SCOPE_IDENTITY,仅限您执行的插入。坦率地说,我从来没有理由使用它。


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

其它参考7


当您使用Entity Framework时,它在内部使用OUTPUT技术返回新插入的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的作用。


此技术(OUTPUT)仅适用于SQL Server 2008或更高版本。

其它参考8


总是使用scope_identity(),不需要任何其他东西。

其它参考9


我不能说其他版本的SQL Server,但在2012年,直接输出工作得很好。你不需要打扰临时表。


INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)


顺便说一下,这种技术在插入多行时也有效。


INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
    (...),
    (...),
    (...)


产量


ID
2
3
4

其它参考10


在插入语句之后,您需要添加它。并确保数据插入的表名。您将获得当前行no插入语句刚刚影响行的行。


IDENT_CURRENT('tableName')