【问题标题】:DBCC CHECKIDENT Sets Identity to 0DBCC CHECKIDENT 将标识设置为 0
【发布时间】:2009-01-23 11:17:29
【问题描述】:

我正在使用此代码来重置桌子上的身份:

DBCC CHECKIDENT('TableName', RESEED, 0)

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

有什么想法吗?

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

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

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

    运行后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);
    

    【讨论】:

    • 非常好,但是在处理多个模式时,您可能需要稍微调整一下以匹配 object_id 而不是使用 OBJECT_NAME() 来查找表的名称:IF EXISTS (SELECT * FROM sys.identity_columns WHERE object_id = OBJECT_ID('Schema.TableName') AND last_value IS NOT NULL)
    【解决方案2】:

    正如您在问题中指出的那样,它是documented behavior。不过我还是觉得很奇怪。我用来重新填充测试数据库,即使我不依赖身份字段的值,在第一次从头开始填充数据库以及删除所有数据并再次填充后,使用不同的值有点烦人。

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

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

    【讨论】:

    • 该链接似乎已失效,当前文档msdn.microsoft.com/en-us/library/ms176057.aspx 表示,这只是 2012 年之前版本的预期行为,但这似乎不是真的(在 2012 版本上测试,兼容性设置为 2012 年,仍然存在问题)。
    【解决方案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
    

    【讨论】:

      【解决方案4】:

      将语句更改为

        DBCC CHECKIDENT('TableName', RESEED, 1)
      

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

      【讨论】:

        【解决方案5】:

        我这样做是为了将值重置为 0,因为我希望我的第一个标识列为 0 并且它正在工作。

        dbcc CHECKIDENT(MOVIE,RESEED,0)
        dbcc CHECKIDENT(MOVIE,RESEED,-1)
        DBCC CHECKIDENT(MOVIE,NORESEED)
        

        【讨论】:

          【解决方案6】:

          参见此处:http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/06/26/fun-with-dbcc-chekident.aspx

          这是记录在案的行为,如果您重新创建表,为什么要运行 CHECKIDENT,在这种情况下跳过该步骤或使用 TRUNCATE(如果您没有 FK 关系)

          【讨论】:

            【解决方案7】:

            我在 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(在这种情况下)。

            【讨论】:

              【解决方案8】:

              只需这样做:

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

              【讨论】:

                【解决方案9】:

                借用 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 = (SELECT TOP 1 CASE WHEN CONVERT(BIGINT, ic.last_value) > 0 THEN 0 ELSE 1 END as reseed FROM sys.identity_columns ic INNER JOIN sys.tables t ON ic.object_id = t.object_id 和 t。 object_id = OBJECT_ID(@tableName))
                【解决方案10】:
                USE AdventureWorks2012;  
                GO  
                DBCC CHECKIDENT ('Person.AddressType', RESEED, 0);  
                GO 
                
                
                
                AdventureWorks2012=Your databasename
                Person.AddressType=Your tablename
                

                【讨论】:

                • 这与 OP 已经做的没有什么不同。解决方案在哪里?
                猜你喜欢
                • 2010-10-21
                • 2014-11-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多