SQL Server的自增列从0开始而不是1

50

我的数据库中有一些表的ID从0开始,尽管在创建表时使用了IDENTITY(1,1)。 这种情况发生在某些表中,而另一些表则没有。 直到今天为止都一直工作正常。

我尝试过重置自增列:

DBCC CHECKIDENT (SyncSession, reseed, 0);

但新记录从0开始。 我已经尝试对所有表格进行此操作,但有些从0开始,有些从1开始。

有什么指示吗?

(我正在使用带高级服务的SQL Server Express 2005)


如果您不断重新生成值,那么您的设计肯定有问题。而且,它从0或1开始又有什么关系呢?这是自动递增,重要的是它是唯一的并且自动分配的,而不是它的起始值是多少。 - HLGEM
2
五年晚了,但是像我一样,OP可能只是在使用已知的数据集进行开发和测试。设计上并没有必要有任何问题。 - GeoffM
3
@HLGEM - 这就是为什么它很重要。如果您正在从数据库记录中填充代码对象,则该对象将使用0作为“ID”属性进行初始化。然后,如果填充成功,它将成为默认值0之外的其他内容。 0可以表示未找到记录或“新”对象。 - nuander
7个回答

55

来自DBCC CHECKIDENT

DBCC CHECKIDENT ( table_name, RESEED, new_reseed_value )
如果自从创建表以来没有插入行,或者使用TRUNCATE TABLE语句删除了所有行,则在运行DBCC CHECKIDENT后插入的第一行将使用new_reseed_value作为标识。否则,插入的下一行将使用new_reseed_value +当前增量值。
因此,对于空表或已截断的表,这是预期的行为。

@GBN,没错,但我所指的是在DELETE后使用DBCC CHECKIDENT(SyncSession,reseed,new_reseed_value);来重置表的种子,将new_reseed_value添加到第一行的当前增量值中。 - James McMahon
15
这并没有真正回答问题。您如何确保种子始终从1开始 - 无论表是否被使用过? - Damien
2
@Damien:这取决于你之前做了什么。由于提到的报价,你不能保证。你必须知道之前的操作。或者明确地截断或重建表格。 - gbn
2
这太疯狂了!我完全不理解,应该始终保持相同的行为方式。天哪,微软... - Ricardo Vigatti
我是这样做的, 我有一个名为tcsapplicable的表格清空表格 tcsapplicable go 重置表格 tcsapplicable 的自增长ID为0 go id 描述 0 否 1 是,销售中 2 是,收据中 3 是,其他中 - sushil.agarwal
显示剩余3条评论

8
如果您传递一个重新种植的值,数据库将从该新值开始标识:
DBCC CHECKIDENT (SyncSession, RESEED, 0); --next record should be 0 + increment

如果您不想传递a值,也可以不用传递,这时将使用IDENTITY(a,b)

DBCC CHECKIDENT (SyncSession, RESEED); --next record should be the seed value 'a'

通常最好的做法是这样的,因为它使表格保持更接近其初始创建状态。


1
但是对于一个空表(或使用 TRUNCATE TABLE 删除所有行),将使编号从0开始而不是1。如何确保自动编号始终从1开始? - Sam
@Sam 有两种方法,一种是在第一个示例中传递新的种子值,另一种是在标识列定义中指定它。 - Keith
1
嗨,Keith,IDENTITY(1,1) 指定的列,在 INSERT 语句之前我总是调用 DBCC CHECKIDENT (AspNetRoles, RESEED, 0);。然而,在第一次插入时(即数据库刚刚创建或使用 TRUNCATE TABLE 删除了所有行),Id 始终为 0。 - Sam
@Sam DBCC CHECKIDENT (AspNetRoles, RESEED, 0) 将把标识重置为0,使用DBCC CHECKIDENT (AspNetRoles, RESEED)将其重置为表定义所指定的值。 - Keith
这对于新的/截断的表不起作用。即使是Redgate Data Compare也使用这种双重DBCC CHECKIDENT“技巧”在生成的脚本中重新设置表格,所以我无法相信它不足够。我发现唯一有效的解决方案是这个 - Gert Arnold

3
这是合理的,因为你已经将标识值更改(重新种子化)为零了。
DBCC CHECKIDENT (SyncSession, reseed, 1)

重新种子标识列,确保第一条新记录从1开始。

1
不,那不对。如果你这样指定1,使用的第一个值将是2! - David M
1
啊,除非你在一个空表上这样做,否则它会采用你指定的值。抱歉!!! - David M
我已经在空表上尝试过这个,现在有些表从1开始,有些从2开始。 - Muxa
留下重新种子后的值将使用当前表上的identity(a,b)值。这是在较低的评论中提到的,但似乎最适合此情况。 - howserss

2

目前被接受的答案只是解释了这个令人烦恼的现象。只有一个答案提供了某种解决方案,但并不实用,因为它需要插入虚拟数据,这使得泛化变得困难。

唯一通用的解决方案是重新设置标识值,然后检查当前标识值,并在其为0时再次重新设置。这可以通过存储过程来完成:

CREATE OR ALTER PROCEDURE ReseedIdentity
    @tableName SYSNAME
AS
BEGIN
    DBCC CHECKIDENT(@tableName, RESEED, 0)
    IF IDENT_CURRENT(@tableName) = 0
    BEGIN
        DBCC CHECKIDENT(@tableName, RESEED, 1)
    END
END

无论是新表、截断还是删除所有记录,这都将始终以身份值1开始新记录。

如果有以更高种子值开头的身份规范,则可以使用稍微高级一点的版本,这是前一个版本的概括:

CREATE OR ALTER PROCEDURE ReseedIdentity
    @tableName SYSNAME
AS
BEGIN
    DECLARE @seed NUMERIC(18,0) = IDENT_SEED(@tableName) - 1;
    DBCC CHECKIDENT(@tableName, RESEED, @seed)
    IF IDENT_CURRENT(@tableName) = @seed
    BEGIN
        SET @seed = @seed + 1
        DBCC CHECKIDENT(@tableName, RESEED, @seed)
    END
END

2

我有同样的问题,在修改数据库后进行备份还原。我只需添加一个虚拟记录,然后将其删除...然后将RESEED设置为0。看起来可以解决问题。


1

试试这个

DECLARE @c TABLE (TanvtechId varchar(10),NewTanvtechId Varchar(10))
INSERT INTO @c
SELECT TanvtechId , Row_Number() OVER (ORDER BY TanvtechId ) from Tanvtech 

UPDATE G
SET G.TanvtechId =a.NewTanvtechId 
FROM Tanvtech as G INNER JOIN @c as a ON a.TanvtechId =G.TanvtechId 

-1
DBCC CHECKIDENT ( Table_Name, RESEED, 0 )

这是一种以零(0)开头的方法,然后删除表中的所有行,并将数据重新放回表中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接