查询以获取下一个身份?

时间:2013-08-12 18:16:40

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

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

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

2 个答案:

答案 0 :(得分:11)

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

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

现在,在两个单独的Management Studio窗口中,首先运行此代码,模拟您在表单上显示的内容,如果您按照接受的答案和所说的“工作”:

SELECT IDENT_CURRENT('dbo.whatever');

注意输出(两者都应为1)。这是对的。 SO FAR

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

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

输出应为1(再次,正确 SO FAR )。

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

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.real_table检索到的值插入ID并在插入列表中包含dbo.dummy_table列。请注意,如果用户看到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表,以提高效率(以及限制性较低的权限)。

答案 1 :(得分:1)

查看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,则不会恢复到先前的设置   语句或批量复制失败,或者事务被回滚。