0

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

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

4

2 回答 2

11

IDENTITY您在应用程序表单上可靠地显示值的唯一方法是INSERT IT FIRSTIDENT_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)。

现在,在另一个窗口中,运行相同的操作,但更改xy. 这个输出现在是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.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?)。无需盲目猜测BookIDfirst 的“下一个”值。

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表(如果有的话)以提高效率(并减少限制性权限)。

于 2013-08-12T18:50:57.860 回答
1

查看SQL SERVER – @@IDENTITY vs SCOPE_IDENTITY() vs IDENT_CURRENT – 检索最后插入的记录标识

请注意差异,如下所述。

我建议你看看使用 IDENT_CURRENT。

IDENT_CURRENT (Transact-SQL)

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

SCOPE_IDENTITY (Transact-SQL)

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

@@IDENTITY (Transact-SQL)

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

于 2013-08-12T18:25:30.877 回答