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
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)
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
@@IDENTITY
返回当前会话中任何表最后生成的身份值,跨越所有作用域。 在这里你需要小心,因为它是跨作用域的。 你可以从触发器中获得一个值,而不是你当前的语句。SCOPE_IDENTITY()
返回当前会话和当前作用域中任何表产生的最后一个身份值。 一般来说,你想使用的是。IDENT_CURRENT('tableName')
返回在任何会话和任何范围内为特定表生成的最后身份值。 这让你可以指定你想要哪个表的值,以防上面两个表不是你需要的(**非常罕见)。 另外,正如@Guy Starbuck提到的,"如果你想获得一个你没有插入记录的表的当前IDENTITY值,你可以使用这个。INSERT "语句的 "OUTPUT "子句5可以让你访问通过该语句插入的每一条记录。 由于它是针对特定语句的,所以它比上面的其他函数更直接。 然而,它有点更繁琐**(你需要插入到一个表变量/临时表,然后查询),而且即使在语句被回滚的错误情况下,它也会给出结果。 也就是说,如果你的查询使用了一个并行的执行计划,这是*唯一能保证获得身份的方法(除非关闭并行)。然而,它是在触发器之前执行的,不能用来返回触发器生成的值。
我相信最安全、最准确的检索插入的id的方法是使用输出子句。
例如(取自下面[MSDN][1]的文章)
[1]: http://msdn.microsoft.com/en-us/library/ms177564.aspx
我'和其他人说的一样,所以大家'都是对的,我只是想说的更清楚一些。
@@IDENTITY
返回你的客户端'连接到数据库的最后插入的东西的id。 大多数情况下,这很好用,但有时触发器会去插入一条你不知道的新行,你'会从这条新行中得到ID,而不是你想要的IDSCOPE_IDENTITY()
解决了这个问题。 它返回的是你向数据库发送的SQL代码中你最后插入的东西的id。 如果触发器去创建额外的行,就不会导致错误的值被返回。 万岁IDENT_CURRENT
返回最后被任何人插入的ID。 如果其他应用程序碰巧在一个不恰当的时间插入了另一行,你会得到那行的ID,而不是你的那行。如果你想安全起见,总是使用
SCOPE_IDENTITY()
。 如果你坚持使用@@IDENTITY
,后来有人决定添加一个触发器,你所有的代码都会被破坏。获取新插入记录的身份的最好(读作:最安全)方法是使用
output
子句: 获取新插入记录的标识的最好(读作:最安全)方法是使用output
子句。添加
到你的insert sql语句的末尾,然后将
会检索到它。
当你使用Entity Framework时,它内部使用 "OUTPUT "技术来返回新插入的ID值。
输出结果存储在临时表变量中,加入回表,并返回出表的行值。
请注意。 我不知道为什么EF会将表内联接回真实的表(在什么情况下两者会不匹配)。
但这就是EF的工作。
这种技术(
OUTPUT
)只在SQL Server 2008或更新的版本上可用。MSDN
@@IDENTITY是使用当前SQL连接插入的最后一个身份。 这是一个很好的值,可以从一个插入存储过程中返回,在这里你只需要为你的新记录插入身份,而不关心之后是否有更多的记录被添加。
SCOPE_IDENTITY是使用当前SQL连接并在当前范围内插入的最后一个身份--也就是说,如果在你插入后有第二个基于触发器的IDENTITY插入,它不会反映在SCOPE_IDENTITY中,只会反映在你执行的插入上。坦率地说,我从来没有理由使用这个。
IDENT_CURRENT(tablename)是最后插入的身份,与连接或范围无关。 如果你想获得一个你没有插入记录的表的当前IDENTITY值,你可以使用这个。
我不能说SQL Server的其他版本,但在2012年,直接输出就可以了。 你不'不需要麻烦的临时表。
顺便说一下,这种技术在插入多行时也可以使用。
产量
总是使用scope_identity(),永远不需要其他东西。
创建一个 "uuid",并将其插入到一列中。 然后你可以很容易地用uuid识别你的行。 这是你唯一可以实现的100%有效的解决方案。 所有其他的解决方案都太复杂了,或者在同样的边缘情况下无法使用。
在你的插入语句后,你需要添加这个。 并确保插入数据的表名,你将得到当前行,而不是刚才插入语句影响的行。
如果你正在寻找最后添加/更新的ID,这可能有点老派,但有很多人使用旧的PHP,更准确地说,是5.5之前。 更多细节可以在 http://php.net/manual/en/function.mysql-insert-id.php 找到。