【问题标题】:Get the last inserted row ID (with SQL statement) [duplicate]获取最后插入的行 ID(使用 SQL 语句)[重复]
【发布时间】:2012-03-17 15:54:28
【问题描述】:

当您在表中插入新记录时,我想获取新创建的 ID。

我读到这个:http://msdn.microsoft.com/en-us/library/ms177564.aspx 但它需要创建临时表。

我想在执行完 INSERT 语句后返回 ID(假设只执行了一次 INSERT)。

例子:

1     Joe      Joe
2     Michael  Mike
3     Zoe      Zoe

在执行INSERT语句时,我想返回创建的ID,意思是4。

能否告诉我如何使用 SQL 语句来做到这一点,否则是不可能的?

【问题讨论】:

  • ID是身份主键吗?
  • @Thit 如果它是主键有什么区别? IDENTITY 和主键是两个完全不同的概念。虽然您可能经常看到它们关联在一起,但它们并不是一回事。我今天刚刚写了一篇关于这个误解的博客,实际上:sqlblog.com/blogs/aaron_bertrand/archive/2012/02/27/…
  • 那么@marc_s 已经为您提供了答案。

标签: sql sql-server


【解决方案1】:

如果您的 SQL Server 表有 INT IDENTITY(或 BIGINT IDENTITY)类型的列,那么您可以使用以下方法获取最新插入的值:

INSERT INTO dbo.YourTable(columns....)
   VALUES(..........)

SELECT SCOPE_IDENTITY()

只要您没有插入另一行,它就可以工作 - 它只是返回在此范围内分发的最后一个 IDENTITY 值。

至少还有两个选项 - @@IDENTITYIDENT_CURRENT - 在 excellent blog post by Pinal Dave here 中详细了解它们的工作原理以及它们的不同之处(并且可能会给您带来意想不到的结果)。

【讨论】:

  • 请注意,SCOPE_IDENTITY() 也可能产生不正确的结果(在并行性下),请参阅support.microsoft.com/kb/2019779 - 上周首次为 2008 R2 SP1 CU5 提供了此修复程序。在所有早期版本中,解决方法是将 maxdop 设置为 1,保持一个碰巧不使用并行性的固定计划(我没有测试过),或者使用输出子句。
  • 我怀疑 Pinal Dave 说 scope_identity 是错误的“将返回您明确创建的最后一个标识值,而不是由触发器或用户定义的函数创建的任何标识” - 我 @ 987654332@ 进入带有触发器的表,该触发器导致插入审计表,scope_identitynull 返回给我。事实上,唯一不返回 null 的选项是 @@identity - 但它给了我审计表的最新 ID!所以这些方法都没有在我的原始插入中返回最新插入的 ID。 SQL Server 2016。
  • @youcantryreachingme:我怀疑在你的代码中的某个地方有错误 - Pinal Dave 通常没有错,而且绝对不是在这一点上.. 为什么不你把你的观察变成一个问题并在这里提问?
  • @youcantryreachingme:好吧,你的表 Client 没有 有任何 IDENTITY 列 - 所以 INSERT INTO Client()... 显然会没有 i> 触发任何正在生成的身份,因此 SCOPE_IDENTITY() 将理所当然地为 NULL :....
  • @marc_s 感谢您如此有力的解释!哇!没想到这么强调!认为主键(唯一的 identifier)可能与表的 identity 列相同(尽管我确实想知道非 @987654341 @ 和复合 PK)。对于其他对此感到困惑的人,这里有一个很好的解释:stackoverflow.com/questions/4293426/…
【解决方案2】:

假设一个简单的表格:

CREATE TABLE dbo.foo(ID INT IDENTITY(1,1), name SYSNAME);

我们可以在表变量中捕获IDENTITY 值以供进一步使用。

DECLARE @IDs TABLE(ID INT);

-- minor change to INSERT statement; add an OUTPUT clause:
INSERT dbo.foo(name) 
  OUTPUT inserted.ID INTO @IDs(ID)
SELECT N'Fred'
UNION ALL
SELECT N'Bob';

SELECT ID FROM @IDs;

这个方法的好处是(a)它处理多行插入(SCOPE_IDENTITY() 只返回最后一个值)和(b)它避免了this parallelism bug,这可能导致错误结果,但目前只在 SQL Server 2008 R2 SP1 CU5 中修复。

【讨论】:

  • 只有当您将编程视为通过创建晦涩的错误而不是工作保障时,正确性才重要
  • 我希望有一种速记语法可以在您知道只有一个结果时将值直接放入变量中,如果有多行(如它适用于某些上下文中的子查询)或仅使用最后一行的值(类似于根据多个连接行的输入更新单行的更新语句的行为)。
  • 在交易中还会出现这种情况吗?
  • @BVernon 当你知道只有一个值时,已经有简写语法:SELECT @ID = SCOPE_IDENTITY();
【解决方案3】:

你可以使用:

SELECT IDENT_CURRENT('tablename')

访问特定表的最新身份。

例如考虑以下代码:

INSERT INTO dbo.MyTable(columns....) VALUES(..........)

INSERT INTO dbo.YourTable(columns....) VALUES(..........)

SELECT IDENT_CURRENT('MyTable')

SELECT IDENT_CURRENT('YourTable')

这将产生相应表的正确值。

它返回表中生成的最后一个IDENTITY 值,无论创建该值的连接如何,也无论生成该值的语句的范围如何。

IDENT_CURRENT不受范围和会话限制;它仅限于指定的表。 IDENT_CURRENT 返回为任何会话和任何范围内的特定表生成的标识值。

【讨论】:

  • 根据您的陈述:“不管创造价值的连接是什么” - 这听起来没用 - 如果另一个连接在我之后插入一行,我会得到他的号码 - 我稍后会使用尝试更新我插入的行,而是更新他的行。对吗?
  • 您使用'和'字符,它们不是有效的SQL。相反,请使用 有效 SQL 的 ' 字符。我已经解决了这个问题。
  • 这是如何获得 49 票的,这超出了我的理解。 IDENT_CURRENT 对于确定插入的最后一行 *I* 完全不可靠,但它是也许获取我或其他任何人插入的最后一行的好方法。见For the last time, NO, you can't trust IDENT_CURRENT()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-07
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多