SQL标识(1,1)从0开始

时间:2014-03-05 14:00:44

标签: sql sql-server tsql identity dbcc

我有一个带有标识集的SQL表:

CREATE TABLE MyTable(
    MyTableID int IDENTITY(1,1) NOT NULL,
    RecordName nvarchar(100) NULL)

这张桌子上发生了一些事情,导致奇怪的行为。我需要找出答案。

发生插入时:

INSERT MyTable(RecordName) 
VALUES('Test Bug')

SELECT SCOPE_IDENTITY() -- returns 0
SELECT * FROM MyTable   -- displays: 0, 'Test Bug'

这是一个问题,因为此插入上方的代码需要第一个ID为1 - 我无法弄清楚IDENTITY(1,1)的最终结果是0

如果(在执行INSERT之前)我检查它返回null的身份:

DBCC CHECKIDENT (MyTable, NORESEED)
  

检查身份信息:当前标识值'NULL',当前列值'NULL'。

我知道几种解决方法;我需要知道桌子是如何进入这种状态的?

我知道CHECKIDENT返回null的唯一方法是,如果刚创建了表,但IDENTITY(1,1)被尊重而INSERT导致SCOPE_IDENTITY()为{{} 1}}。

如果我强制1作为当前种子(0-1),我可以将DBCC CHECKIDENT (MyTable, RESEED, -1)作为下一个ID,但检查会报告当前{ {1}}种子(而不是空),所以不能发生什么。

数据库是如何进入列SET IDENTITY_INSERT MyTable ON的状态,-1返回null,但下一个IDENTITY(1,1)导致DBCC CHECKIDENT (MyTable, NORESEED)INSERT

1 个答案:

答案 0 :(得分:11)

我希望有人/某事已经运行:

DBCC CHECKIDENT ('dbo.MyTable', RESEED, 0);

如果您运行以下内容:

CREATE TABLE dbo.MyTable(
    MyTableID int IDENTITY(1,1) NOT NULL,
    RecordName nvarchar(100) NULL
);

DBCC CHECKIDENT ('dbo.MyTable', RESEED, 0);
DBCC CHECKIDENT ('dbo.MyTable', NORESEED);

第二个CHECKIDENT仍会返回NULL

  

检查身份信息:当前标识值'NULL',当前列值'NULL'。

然而,下一个标识值将为0.这是documented behaviour,MSDN声明:

  

当前标识值设置为new_reseed_value。 如果自创建表以来没有向表中插入任何行,则执行DBCC CHECKIDENT后插入的第一行将使用new_reseed_value作为标识。否则,插入的下一行将使用new_reseed_value + 1.如果new_reseed_value的值小于标识列中的最大值,则将在对该表的后续引用上生成错误消息2627。

这仅适用于新创建/截断的表,其中last_value中的sys.identity_columns列仍为NULL。如上所述,如果要插入一行,删除它,然后重新设置为0,则新标识仍为1.

完整测试脚本

IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL
    DROP TABLE dbo.T;

CREATE TABLE dbo.T(ID INT IDENTITY(1,1) NOT NULL);
INSERT dbo.T OUTPUT inserted.* DEFAULT VALUES;
-- OUTPUTS 1

DELETE dbo.T;
DBCC CHECKIDENT ('dbo.T', RESEED, 0);
INSERT dbo.T OUTPUT inserted.* DEFAULT VALUES;
-- OUTPUTS 1

TRUNCATE TABLE dbo.T;
DBCC CHECKIDENT ('dbo.T', RESEED, 0);
INSERT dbo.T OUTPUT inserted.* DEFAULT VALUES;
-- OUTPUTS 0