9

我有一个带有标识集的 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.

0或者,如果我强制-1作为当前种子(DBCC CHECKIDENT (MyTable, RESEED, -1)或 with ),我可以获得下一个 ID,SET IDENTITY_INSERT MyTable ON但随后检查报告当前-1种子(而不是 null),所以这不可能是发生的事情。

数据库是如何进入该列的状态IDENTITY(1,1)DBCC CHECKIDENT (MyTable, NORESEED)返回 null,但下一个INSERT原因SCOPE_IDENTITY()0

4

1 回答 1

15

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

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。这是记录在案的行为,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
于 2014-03-05T14:32:09.020 回答