DBCC CHECKIDENT将标识设置为0


75

我正在使用以下代码来重置表的身份:

DBCC CHECKIDENT('TableName', RESEED, 0)

在大多数情况下,这都可以正常工作,我将第一个插入项插入1到Id列中。但是,如果我删除数据库并使用我编写的脚本重新创建它,然后调用DBCC CHECKIDENT,则插入的第一项的ID为0。

有任何想法吗?

编辑:经过研究,我发现我没有正确阅读文档-“当前标识值设置为new_reseed_value。如果自创建以来没有将任何行插入表,执行DBCC CHECKIDENT后插入的第一行将使用new_reseed_value作为标识。否则,插入的下一行将使用new_reseed_value + 1。

Answers:


26

正如您在问题中指出的那样,这是有据可查的行为。我仍然觉得很奇怪。我用来重新填充测试数据库,即使我不依赖标识字段的值,当从头开始第一次填充数据库以及删除所有数据并再次填充之后,具有不同的值还是有点令人讨厌。

一个可能的解决方案是使用truncate来清理表而不是删除表。但是然后您需要删除所有约束并在之后重新创建它们

这样,它始终表现为新创建的表,因此无需调用DBCC CHECKIDENT。第一个标识值将是表定义中指定的值,并且无论您是第一次插入数据还是第N个数据都将相同。


2
该链接似乎已失效,当前文档msdn.microsoft.com/en-us/library/ms176057.aspx表示,这只是2012年之前版本的预期行为,但事实并非如此(测试2012版本,兼容性设置为2012,仍然存在问题)。
jmoreno

67

您对问题的编辑所写的内容是正确的。

运行后DBCC CHECKIDENT('TableName', RESEED, 0)
-新创建的表将以标识0开头
-现有表将以标识1继续

解决方案在下面的脚本中,有点穷人截断:)

-- Remove all records from the Table
DELETE FROM TableName

-- Use sys.identity_columns to see if there was a last known identity value
-- for the Table. If there was one, the Table is not new and needs a reset
IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'TableName' AND last_value IS NOT NULL) 
    DBCC CHECKIDENT (TableName, RESEED, 0);

2
很好,但有多种模式打交道时,你可能需要调整这一点来匹配object_id,而不是使用OBJECT_NAME()查找表的名称: IF EXISTS (SELECT * FROM sys.identity_columns WHERE object_id = OBJECT_ID('Schema.TableName') AND last_value IS NOT NULL
尼克-

5

将声明更改为

  DBCC CHECKIDENT('TableName', RESEED, 1)

它将从2(或重新创建表时为1)开始,但永远不会为0。



3

您无法使用单个命令来设置/重置标识列来涵盖表是否已插入记录的两种情况,这似乎很荒谬。直到我偶然发现了这个问题,我才明白自己的行为!

我的解决方案(难看但可行)是显式检查sys.identity_columns.last_value表(它告诉您表是否已插入记录),并DBCC CHECKIDENT在每种情况下调用适当的命令。如下:

DECLARE @last_value INT = CONVERT(INT, (SELECT last_value FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = 'MyTable'));
IF @last_value IS NULL
    BEGIN
        -- Table newly created and no rows inserted yet; start the IDs off from 1
        DBCC CHECKIDENT ('MyTable', RESEED, 1);
    END
ELSE
    BEGIN
        -- Table has rows; ensure the IDs continue from the last ID used
        DECLARE @lastValUsed INT = (SELECT ISNULL(MAX(ID),0) FROM MyTable);
        DBCC CHECKIDENT ('MyTable', RESEED, @lastValUsed);
    END


1

我已在SQL中使用此功能将IDENTITY设置为特定值:-

DECLARE @ID int = 42;
DECLARE @TABLENAME  varchar(50) = 'tablename'

DECLARE @SQL nvarchar(1000) = 'IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = '''+@TABLENAME+''' AND last_value IS NOT NULL)
    BEGIN
        DBCC CHECKIDENT('+@TABLENAME+', RESEED,' + CONVERT(VARCHAR(10),@ID-1)+');
    END
    ELSE
    BEGIN
        DBCC CHECKIDENT('+@TABLENAME+', RESEED,' + CONVERT(VARCHAR(10),@ID)+');
    END';
EXEC (@SQL);

并在C#中设置特定值:-

SetIdentity(context, "tablename", 42);
.
.
private static void SetIdentity(DbContext context, string table,int id)
{
    string str = "IF EXISTS (SELECT * FROM sys.identity_columns WHERE OBJECT_NAME(OBJECT_ID) = '" + table
        + "' AND last_value IS NOT NULL)\nBEGIN\n";
    str += "DBCC CHECKIDENT('" + table + "', RESEED," + (id - 1).ToString() + ");\n";
    str += "END\nELSE\nBEGIN\n";
    str += "DBCC CHECKIDENT('" + table + "', RESEED," + (id).ToString() + ");\n";
    str += "END\n";
    context.Database.ExecuteSqlCommand(str);
}

这建立在以上答案的基础上,并始终确保下一个值为42(在这种情况下)。


1

从Zyphrax的答案借来的...

USE DatabaseName

DECLARE @ReseedBit BIT = 
    COALESCE((SELECT SUM(CONVERT(BIGINT, ic.last_value))
                FROM sys.identity_columns ic
                INNER JOIN sys.tables t ON ic.object_id = t.object_id), 0)
DECLARE @Reseed INT = 
CASE 
    WHEN @ReseedBit = 0 THEN 1 
    WHEN @ReseedBit = 1 THEN 0 
END

DBCC CHECKIDENT ('dbo.table_name', RESEED, @Reseed);

注意事项:此方法适用于使用枚举类型定义表初始化数据库的参考数据填充情况,其中这些表中的ID值必须始终从1开始。第一次创建数据库时(例如,在SSDT- DB发布)@Reseed必须为0,但是在重置数据(即删除数据并重新插入数据)时,@ Reseed必须为1。因此,此代码旨在用于存储过程中以重置DB数据,这可以可以手动调用,也可以从SSDT-DB项目的部署后脚本中调用。这样,参考数据插入仅在一个位置定义,而不仅限于在发布过程中仅用于后期部署,还可以用于后续使用(以支持开发人员和自动化测试等)。


有一种更简单的方法可以做相同的事情,请原谅我的格式化。DECLARE @Reseed INT =(当转换(BIGINT,ic.last_value)> 0则选择TOP 1情况,然后从sys.identity_columns ic INNER JOIN sys.tables重新设置为0结束1结束ic.object_id = t.object_id和t。 object_id = OBJECT_ID(@tableName))
Nikhil Doomra

0

只需执行以下操作:

IF EXISTS (SELECT * FROM tablename)
BEGIN
    DELETE from  tablename
    DBCC checkident ('tablename', reseed, 0)
END

-2
USE AdventureWorks2012;  
GO  
DBCC CHECKIDENT ('Person.AddressType', RESEED, 0);  
GO 



AdventureWorks2012=Your databasename
Person.AddressType=Your tablename

这与OP已经没有什么不同。解决方案在哪里?
格特·阿诺德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.