获取IDENTITY插入行的最佳方法是什么?
我知道@@IDENTITY和IDENT_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
(...),
(...),
(...) |
产量
总是使用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(); |