关于sql:获取插入行标识的最佳方法?

Best way to get identity of inserted row?

获取IDENTITY插入行的最佳方法是什么?

我知道@@IDENTITYIDENT_CURRENT以及SCOPE_IDENTITY,但不了解每个附带的利弊。

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


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

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

  • IDENT_CURRENT('tableName')返回在任何会话和任何范围内为特定表生成的最后一个标识值。这使您可以指定您想要该值的表,以防上述两个不是您需要的(非常罕见)。此外,正如@Guy Starbuck所提到的,"如果你想获得未插入记录的表的当前IDENTITY值,你可以使用它。"

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


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

例如(摘自以下MSDN文章)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


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

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

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

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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)


1
SELECT CAST(scope_identity() AS INT);

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

1
NewId = command.ExecuteScalar()

将检索它。


使用Entity Framework时,它在内部使用OUTPUT技术返回新插入的ID值

1
2
3
4
5
6
7
8
9
10
11
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或更高版本。


MSDN

@@IDENTITY, SCOPE_IDENTITY, and IDENT_CURRENT are similar functions in that they return the last value inserted into the IDENTITY column of a table.

@@IDENTITY and SCOPE_IDENTITY will return the last identity value generated in any table in the current session. However, SCOPE_IDENTITY returns the value only within the current scope; @@IDENTITY is not limited to a specific scope.

IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope. For more information, see IDENT_CURRENT.

  • IDENT_CURRENT是一个以表为参数的函数。
  • 当您在表格上有触发器时,@@ IDENTITY可能会返回令人困惑的结果
  • SCOPE_IDENTITY大部分时间都是你的英雄。

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

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

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


我无法与其他版本的SQL Server通信,但在2012年,直接输出工作正常。您不需要打扰临时表。

1
2
3
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)

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

1
2
3
4
5
6
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
    (...),
    (...),
    (...)

产量

1
2
3
4
ID
2
3
4


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


创建uuid并将其插入列。然后,您可以使用uuid轻松识别您的行。


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

1
IDENT_CURRENT('tableName')


如果您正在寻找添加/更新的最后一个ID,这可能是一个古老的学校,但有很多人使用较旧的PHP,Pre 5.5更精确。更多细节可以在http://php.net/manual/en/function.mysql-insert-id.php找到

1
$last = mysql_insert_id();