重新生成丢失的标识值

Regenerate lost identity value

如果语句在事务块内失败,是否有办法重新创建 SQL 服务器 table 的标识值?

请看下面的代码:

DECLARE @IdentityTable AS TABLE (ID INT IDENTITY(1, 1), Description VARCHAR(50))

INSERT INTO @IdentityTable (Description) 
VALUES('Test1')

BEGIN TRY 
BEGIN TRANSACTION IdentityTest
    INSERT INTO @IdentityTable (Description) 
    VALUES('Test2')

    INSERT INTO @IdentityTable (Description) 
    VALUES(1/0)

    COMMIT TRANSACTION IdentityTest
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION IdentityTest
END CATCH

INSERT INTO @IdentityTable (Description) 
VALUES('Test4')

SELECT * FROM @IdentityTable

3 号身份因 ROLLBACK TRANSACTION 而丢失。有可能重新获得吗?

您正在尝试使用 IDENTITY 属性 生成连续数字,并维护它;这不是 IDENTITY 的目的。它旨在提供基于当前种子的增量值(它自己(没有 PRIMARY KEY 约束或 UNIQUE INDEX),它甚至不保证唯一性,因为种子可以更改(感谢 HoneyBadger 一大早就提醒我)).

如果 INSERT 失败,IDENTITY 的值仍会递增。此外,如果您要从 table 到 DELETE 行,那不会导致每个 "latter" 行的 ID 都相应地更新;那么你也会有差距。

确保获得递增值的唯一保证方法是在 运行 时间 使用 ROW_NUMBER 之类的函数。例如:

SELECT ROW_NUMBER() OVER (ORDER BY ID) AS cID,
       Description
FROM YourTable;

文档的 Remarks 部分明确指出连续值 not guarenteed:

Identity columns can be used for generating key values. The identity property on a column guarantees the following:

...

Consecutive values within a transaction – A transaction inserting multiple rows is not guaranteed to get consecutive values for the rows because other concurrent inserts might occur on the table. If values must be consecutive then the transaction should use an exclusive lock on the table or use the SERIALIZABLE isolation level.

Consecutive values after server restart or other failures – SQL Server might cache identity values for performance reasons and some of the assigned values can be lost during a database failure or server restart. This can result in gaps in the identity value upon insert. If gaps are not acceptable then the application should use its own mechanism to generate key values. Using a sequence generator with the NOCACHE option can limit the gaps to transactions that are never committed.

Reuse of values – For a given identity property with specific seed/increment, the identity values are not reused by the engine. If a particular insert statement fails or if the insert statement is rolled back then the consumed identity values are lost and will not be generated again. This can result in gaps when the subsequent identity values are generated.