【问题标题】:Query to get the next identity? [closed]查询以获得下一个身份? [关闭]
【发布时间】:2013-08-14 04:05:19
【问题描述】:

查询以获得下一个身份?这对于没有删除记录的表是可能的:

SELECT TOP 1 EMPID + 1 FROM Employee ORDER BY EMPID DESC

如果有删除数据,我将如何获得下一个身份?例如我有一个这样的表:

EMPID    NAME
4001     someName
4002     someName
4003 ----------------------- this is deleted
4004     someName
4005     someName
4006     someName
4007     someName
4008     someName
4009 ----------------------- this is deleted
4010 ----------------------- this is deleted

输出必须是 4011

【问题讨论】:

  • 这很愚蠢。如果您在最终执行插入时查询下一个身份可能是什么,那么其他人可能已经生成了一个新值(提交或回滚),从而使您的猜测完全不准确。无论如何,出示身份证有什么意义?身份值应该是最终用户不需要知道或关心的透明代理。如果他们这样做了,则提交插入,然后然后向他们展示他们得到了什么,而不是向他们展示他们可能得到什么。
  • SQL Server 不会“回收”已删除的标识值 - 这是一件好事!
  • 先执行插入,然后然后显示在您的表单上。为什么您的用户需要在您将 ID 值分配给他们之前知道他们获得什么 ID 值?如果错了,这对他们有什么帮助?
  • 看我的第一条评论!执行插入,然后检索实际使用的标识值。
  • @Karlx 你完全没有抓住重点。通过打开两个管理工作室窗口来模拟您的应用程序的两个用户。在每一个中运行您的IDENT_CURRENT 查询并输出结果。现在,在一个窗口中插入表格,然后插入另一个窗口,在这两种情况下检查SCOPE_IDENTITY()。他们都 100% 不可能匹配 IDENT_CURRENT 输出,但是您在表单上向两个用户显示了该 ID。请注意,在这两个会话中,您都没有删除任何内容。

标签: sql tsql sql-server-2008-r2 identity-column


【解决方案1】:

在应用程序表单上可靠地显示IDENTITY 值的唯一方法是先插入IDENT_CURRENT 可能在您是唯一测试它的人时对您有所帮助,但我可以向您保证,一旦多个用户使用您的应用程序,这将很快分崩离析。这也很容易证明。创建下表:

CREATE TABLE dbo.whatever(ID INT IDENTITY(1,1), blat CHAR(1));

现在,在两个单独的 Management Studio 窗口中,首先运行此代码,它会模拟您将在表单上显示的内容,如果您遵循接受的答案以及您所说的“有效”:

SELECT IDENT_CURRENT('dbo.whatever');

注意输出(两者都应该是1)。这是对的。 到目前为止

现在,在一个窗口中运行:

INSERT dbo.whatever(blat) SELECT 'x';
SELECT SCOPE_IDENTITY();

输出应该是1(这也是正确的SO FAR)。

现在,在另一个窗口中,运行相同的操作,但将 x 更改为 y。这个输出现在是2呃-哦。这与您在该用户的表单上显示的内容不符。您还可以通过查看表中有两行来验证这一点,12 作为 IDENTITY 值:

SELECT ID, blat FROM dbo.whatever;

执行此操作的正确方法也是唯一的方法是插入一行,检索值,然后 将其显示在表单上。如果您需要事先向他们显示一些代理值(不知道为什么需要这样做,或者为什么您的最终用户无论何时检索它都需要知道这个值 - 为什么用户关心 ID 是什么?),然后创建一个单独的表并在那里生成您的 IDENTITY 值。

CREATE TABLE dbo.dummy_table(ID INT IDENTITY(1,1) PRIMARY KEY);
GO
CREATE TABLE dbo.real_table(ID INT PRIMARY KEY, ...other columns...);
GO

现在,当您想在表单上显示“下一个”ID 时,可以使用以下方法:

INSERT dbo.dummy_table DEFAULT VALUES;
SELECT SCOPE_IDENTITY();

然后当用户填写其余信息时,您可以使用从dbo.dummy_table 检索到的值插入dbo.real_table 并在插入列表中包含ID 列。请注意,如果用户看到一个 ID 并且没有点击保存,这仍然会导致空白,但该 ID 现在没有意义,因为它从未进入真实表格 - 并且其他任何人都不可能已经看到了(与 IDENT_CURRENTMAX+1 和其他构思不周的“首先检查价值”技术可能发生的情况不同)。

如果您的实际目标是将图书的三份副本插入到另一个表中,则解决方案非常简单,仍然需要您先插入图书。假设您有参数来表示书名和份数(以及我确定的其他参数):

DECLARE @Copies INT, @name NVARCHAR(32);

SELECT @Copies = 3, @name = N'Moby Dick';

现在,我们可以插入dbo.Books 表,并使用输出将多行插入另一个表(dbo.Accession?)。无需先盲目猜测BookID的“下一个”值。

DECLARE @BookID INT;

INSERT dbo.Books(name, copies, whatever...) SELECT N'Moby Dick', 3, ...;

SELECT @BookID = SCOPE_IDENTITY();

INSERT dbo.Accession(AccessionID, BookID)
  SELECT rn, @BookID
  FROM
  (
    SELECT TOP (@Copies) rn = ROW_NUMBER() OVER (ORDER BY [object_id])
    FROM sys.columns ORDER BY [object_id]
  ) AS y;

这使用了从目录视图生成多行的技巧,但您也可以使用内置的Numbers 表(如果有的话)以提高效率(并减少限制性权限)。

【讨论】:

  • 没有。不会显示这些 ID。它只会存储在 int 中。
  • 是的,但是你说这样做不好,所以我改变了主意。我的问题是这个。在我的应用程序中,用户将插入一本书。例如 someBook 将插入 3 个副本。 Table1.BookID = 1,Table1.Copy = 3,然后在另一个表中,这 3 本书将有它们的主键,因此它将是 Table2.AccessionID = 1,2,3 Table2.BookID = 1,1,1。
  • @Karlx 请开始一个新问题,准确描述您的实际问题。这个问题似乎与这个 AccessionID 问题几乎没有关系。'
  • 我编辑了我的问题,先生
  • @Karlx 我的答案不需要更改,但我提出不同问题的原因是因为现在您的问题实际上与您的问题标题无关,并且已经有很多人回答了您的问题编辑前的原始问题。在引起注意之后完全改变您的问题是不公平的。在您进行其他任何事情之前,请阅读此主题:meta.stackexchange.com/questions/43478/…
【解决方案2】:

看看SQL SERVER – @@IDENTITY vs SCOPE_IDENTITY() vs IDENT_CURRENT – Retrieve Last Inserted Identity of Record

请注意差异,如下所述。

我建议您使用 IDENT_CURRENT。

IDENT_CURRENT (Transact-SQL)

返回为指定表生成的最后一个标识值或 看法。生成的最后一个身份值可以用于任何会话和任何 范围。

SCOPE_IDENTITY (Transact-SQL)

返回插入到标识列中的最后一个标识值 相同的范围。作用域是一个模块:一个存储过程、触发器、 函数或批处理。因此,如果两个语句在同一范围内 它们在同一个存储过程、函数或批处理中。

@@IDENTITY (Transact-SQL)

在 INSERT、SELECT INTO 或批量复制语句完成后, @@IDENTITY 包含由 陈述。如果该语句不影响任何具有标识的表 列,@@IDENTITY 返回 NULL。如果插入多行, 生成多个标识值,@@IDENTITY 返回最后一个 生成的标识值。如果语句触发一个或多个触发器 执行生成标识值的插入,调用@@IDENTITY 在语句返回最后一个标识值之后立即 由触发器生成。如果在插入后触发触发器 对具有标识列的表执行操作,并且触发器插入 进入另一个没有标识列的表,@@IDENTITY 返回第一个插入的标识值。 @@IDENTITY 值 如果 INSERT 或 SELECT INTO 语句或批量复制失败,或者事务回滚。

【讨论】:

  • 谢谢。此 SELECT IDENT_CURRENT('Employee')+1 有效
  • @KarlxSwanovski 是的,当您是唯一的用户时,它可能会起作用。当您有并发使用时,它将绝对不起作用
  • @Astander 你能解释一下为什么你建议调查IDENT_CURRENT吗?正如我在回答中概述的那样,如果有多个用户,这可能会产生非常错误的结果。
  • 不不不。我想我被误解了。在将 ID 插入数据库之前,我不建议将此作为向用户显示 ID 的尝试。这是完全错误的。所以@AaronBertrand,如果您要列出,那不是建议。事实上,我绝不会推荐这样的东西。
猜你喜欢
  • 2021-09-06
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
相关资源
最近更新 更多