获取插入行身份的最佳方法?
什么是插入行的身份的最佳方式?
我知道@@IDENTITY
和IDENT_CURRENT
和SCOPE_IDENTITY
但不明白每个附带的优点和缺点。
有人可以解释一下这些差异,什么时候我应该使用它们?
-
@@IDENTITY
返回当前会话中任何表中为所有作用域生成的最后一个标识值。 你需要小心 ,因为它跨越了范围。 您可以从触发器中获取值,而不是当前的语句。 -
SCOPE_IDENTITY()
返回为当前会话中的任何表和当前范围生成的最后一个标识值。 一般来说你想用什么 。 -
IDENT_CURRENT('tableName')
返回为任何会话和任何作用域中的特定表生成的最后一个标识值。 这可以让你指定你想从哪个表中获得值,以防上面的两个不是你所需要的( 非常less见 )。 另外,正如@ Guy Starbuck所说:“如果你想为没有插入logging的表获取当前的IDENTITY值,你可以使用它。 -
INSERT
语句的OUTPUT
子句将允许您访问通过该语句插入的每一行。 由于它是作为特定语句的范围,所以比上述其他函数更直接 。 然而,它有点冗长 (你需要插入到一个表variables/临时表中,然后查询),即使在语句被回滚的错误情况下,它也会给出结果。 也就是说,如果您的查询使用并行执行计划,这是获取身份唯一保证的方法 (closures并行性的缺点)。 但是,它在触发器之前执行,不能用于返回触发器生成的值。
我相信检索插入的id最安全和最准确的方法将使用输出子句。
例如(取自以下MSDN文章)
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。 如果触发器去创build额外的行,它们不会导致返回错误的值。 万岁
IDENT_CURRENT
返回任何人插入的最后一个ID。 如果其他应用恰好在不幸的时间插入另一行,则会得到该行的ID而不是您的ID。
如果你想安全玩,总是使用SCOPE_IDENTITY()
。 如果你坚持使用@@IDENTITY
并且稍后有人决定添加一个触发器,那么你所有的代码都会中断。
获取新插入行的身份的最佳(读取:最安全)方法是使用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)
加
SELECT CAST(scope_identity() AS int);
然后到你的插入sql语句的末尾
NewId = command.ExecuteScalar()
将检索它。
MSDN
@@ IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT是相似的函数,它们返回插入到表的IDENTITY列中的最后一个值。
@@ IDENTITY和SCOPE_IDENTITY将返回当前会话中任何表中生成的最后一个标识值。 但是,SCOPE_IDENTITY仅在当前范围内返回值; @@ IDENTITY不限于特定的范围。
IDENT_CURRENT不受范围和会话的限制; 它仅限于指定的表格。 IDENT_CURRENT返回为任何会话和任何作用域中的特定表生成的标识值。 有关更多信息,请参阅IDENT_CURRENT。
- IDENT_CURRENT是一个以表格作为参数的函数。
- 在桌面上有触发器时, @@ IDENTITY可能会返回混淆结果
- SCOPE_IDENTITY大部分时间都是你的英雄。
@@ IDENTITY是使用当前SQL连接插入的最后一个标识。 从插入存储过程返回这是一个很好的价值,在这里你只需要为新logging插入标识,而不必关心后面是否添加了更多的行。
SCOPE_IDENTITY是使用当前SQL连接插入的最后一个标识,在当前作用域中 – 也就是说,如果在插入之后基于触发器插入了第二个IDENTITY,则不会反映在SCOPE_IDENTITY中,只有您执行的插入。 坦率地说,我从来没有理由使用这个。
IDENT_CURRENT(表名)是插入的最后一个标识,无论连接或范围如何。 如果你想为没有插入logging的表获取当前的IDENTITY值,你可以使用它。
总是使用scope_identity(),从来没有任何其他的需要。
当您使用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
输出结果存储在一个临时表variables中,并返回到表中,并将行值从表中返回。
注:我不知道为什么EF内部将短暂的表加回到真正的表(在什么情况下两个不匹配)。
但这就是EF所做的。
此技术( OUTPUT
)仅适用于SQL Server 2008或更新版本。