Best way to get identity of inserted row?
获取
我知道
有人可以解释一下这些差异,以及何时应该使用它们?
-
@@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 |
我说的和其他人一样,所以每个人都是对的,我只是想让它更清楚。
大部分时间这种方法都可以正常工作,但有时触发器会插入一个你不知道的新行,你将从这个新行中获取ID,而不是你想要的那个
如果您想安全地玩,请始终使用
获取新插入行的标识的最佳(读取:最安全)方法是使用
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时,它在内部使用
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所做的。
此技术(
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(),不需要任何其他东西。
创建
在插入语句之后,您需要添加它。并确保数据插入的表名。您的插入语句刚才会影响当前行的行。
1 | IDENT_CURRENT('tableName') |
如果您正在寻找添加/更新的最后一个ID,这可能是一个古老的学校,但有很多人使用较旧的PHP,Pre 5.5更精确。更多细节可以在http://php.net/manual/en/function.mysql-insert-id.php找到
1 | $last = mysql_insert_id(); |