SQL Server 标识列值从 0 而不是 1 开始

Posted

技术标签:

【中文标题】SQL Server 标识列值从 0 而不是 1 开始【英文标题】:SQL server identity column values start at 0 instead of 1 【发布时间】:2010-10-18 00:03:35 【问题描述】:

我遇到了一个奇怪的情况,我的数据库中的一些表的 ID 从 0 开始,即使 TABLE CREATE 具有 IDENTITY(1,1)。 对于某些表是这样,但对于其他表则不然。 它一直有效到今天。

我已尝试重置身份列:

DBCC CHECKIDENT (SyncSession, reseed, 0);

但新记录以 0 开头。 我已尝试对所有表执行此操作,但有些仍从 0 开始,有些仍从 1 开始。

任何指针?

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

【问题讨论】:

如果您不断地重新设定值,那么您的设计就有问题。如果它以 0 或 1 开头,为什么重要?这是一个自动增量,值是什么无关紧要,它是唯一的并且是自动分配的。 晚了五年,但像我一样,OP 可能只是在使用一组已知的数据进行开发和测试。设计不一定有什么问题。 @HLGEM - 这就是它重要的原因。如果您正在从数据库记录填充代码对象,该对象将使用 0 的“ID”属性进行初始化。然后,如果填充成功,它将是默认值 0 以外的值。0 表示未找到记录或一个“新”对象。 【参考方案1】:

这是合乎逻辑的,因为您已将身份值更改(重新设置)为零?

DBCC CHECKIDENT (SyncSession, reseed, 1)

将重新设定您的身份列,并确保第一条新记录以 1 开头。

【讨论】:

不,这是不对的。如果您以这种方式指定 1,则使用的第一个值将是 2! 啊,除非您在空表上执行此操作,否则它将采用您指定的值。道歉!!! 我在空表上试过这个,现在有些表从 1 开始,有些从 2 开始。 在reseed out后留下值将使用当前表上的identity(a,b)值。较低的评论提到了这一点,但似乎最适合这种情况。【参考方案2】:

来自DBCC CHECKIDENT

DBCC CHECKIDENT ( table_name, RESEED, new_reseed_value )

如果没有行被插入到 自创建以来的表,或全部 行已通过使用 TRUNCATE TABLE 语句,第一个 运行 DBCC 后插入的行 CHECKIDENT 使用 new_reseed_value 作为 身份。否则,下一行 插入使用 new_reseed_value + 当前增量值。

因此,这是空表或截断表的预期结果。

【讨论】:

仅供参考,DELETE FROM 语句将使用后一种行为,“插入的下一行使用 new_reseed_value + 当前增量值”。 DELETE 不会重置种子。你是这个意思吗? 这并没有真正回答问题。您如何确保种子始终从 1 开始 - 无论该表是否已使用? @Damien:这取决于你以前做过什么。由于提及的报价,您无法保证。您已经知道以前的操作。或显式 TRUNCATE 或重建表。 这太疯狂了!对我来说没有意义,应该总是以同样的方式行事。天哪,微软...【参考方案3】:

我有同样的问题,修改数据库后从备份恢复。我只是添加一个虚拟记录,然后将其删除...然后将 RESEED 设置为 0。似乎可以工作。

【讨论】:

【参考方案4】:

试试这个

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 

【讨论】:

【参考方案5】:

如果您传递一个重新种子值,数据库将从该新值开始标识:

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'

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

【讨论】:

但是对于空表(或使用 TRUNCATE TABLE 删除所有行)会使数字从 0 开始而不是 1。如何确保自动编号始终从 1 开始? @Sam 有两种方式,或者通过第一个示例传递新的种子值,或者在标识列定义中指定它。 嗨 Keith,IDENTITY(1,1) 指定的列,我总是在 INSERT 声明之前调用 DBCC CHECKIDENT (AspNetRoles, RESEED, 0);。但是,在第一次插入时(即数据库刚刚创建或使用 TRUNCATE TABLE 删除所有行),Id 始终为 0。 @Sam DBCC CHECKIDENT (AspNetRoles, RESEED, 0) 将身份重置为0,使用DBCC CHECKIDENT (AspNetRoles, RESEED) 将其重置为表定义状态。 这不适用于新的/截断的表。甚至 Redgate Data Compare 也使用这种双重 DBCC CHECKIDENT “技巧”在生成的脚本中重新设置表,所以我简直不敢相信这还不够。我发现唯一可行的解​​决方案是this。【参考方案6】:
DBCC CHECKIDENT ( Table_Name, RESEED, 0 )

这是一种以Zero(0) 开头的id,然后从表中删除所有行并再次将数据放回表中。

【讨论】:

【参考方案7】:

目前接受的答案只解释了这种烦人的现象。只有一个答案提供了某种解决方案,但并不真正实用,因为它需要一个虚拟插入,这使得它很难一概而论。

唯一通用的解决方案是重新设定标识值,然后检查当前标识值并在为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

【讨论】:

以上是关于SQL Server 标识列值从 0 而不是 1 开始的主要内容,如果未能解决你的问题,请参考以下文章

如何更改sql server中的默认列值

如何获得价值比多列值,而不是使用从SQL Server复合键字段

有没有办法确保 SQL Server 标识列值即使在多次服务器重新启动后也始终保持一致?

SQL Server中的标识列

在 SQL Server Compact 中返回标识

使用sql语句创建修改SQL Server标识列(即自动增长列)