【问题标题】:Reset AutoIncrement in SQL Server after Delete删除后在 SQL Server 中重置 AutoIncrement
【发布时间】:2010-10-05 08:07:05
【问题描述】:

我从 SQL Server 数据库的表中删除了一些记录。

表格中的 ID 如下所示:

99 100 101 1200 1201……

我想删除后面的记录(ID > 1200),然后我想重置自动增量,以便下一个自动生成的 ID 为 102。所以我的记录是连续的,有没有办法在 SQL Server 中做到这一点?

【问题讨论】:

  • 请不要说“不要这样做”。当我问如何做某事而我得到的只是不做时,我讨厌它。是的,重置身份可能会导致外键问题,但前提是您不知道相应的数据库和程序。在计划删除后重置身份有很好的理由——他们被称为审计员。审计员讨厌看到漏洞,所以要填补漏洞,以可控的方式进行,并确保保持外键约束。
  • @spyder,您是否知道如果回滚记录插入而不仅仅是删除,您将有间隙?您无法通过自动增量避免间隙,尝试是愚蠢的。我曾在一家审计机构工作过,称职的审计员可以向他们解释这一点。此外,如果您有适当的审计表,他们可以看到这些记录发生了什么。或者,如果出于法律原因必须不存在任何漏洞(这种情况很少见),那么只有不称职的开发人员才会使用自动增量,而审计人员会感到不安。

标签: sql-server auto-increment delete-row


【解决方案1】:

发出以下命令,将 mytable 重新设置为从 1 开始:

DBCC CHECKIDENT (mytable, RESEED, 0)

在在线书籍(BOL、SQL 帮助)中了解它。另请注意,您的记录不要高于您设置的种子。

【讨论】:

  • ... 因为这些记录的 id 会很高兴地再次被重用,造成一团糟。
  • 其实要从1开始ID,需要使用0:DBCC CHECKIDENT (mytable, RESEED, 0)
  • "DBCC CHECKIDENT (table_name)" 将种子设置为表中的最高标识,而不是您不必“小心”
  • @user1027167 不,您的回答对我不起作用。它在内部保存的最高 ID 上不断增加。在我的情况下,我必须明确使用“RESEED,18”才能获得“19”作为下一个 ID。如果没有它,它会在“29”上愉快地递增。
  • DBCC CHECKIDENT (table_name) 仅在标识值低于列中的最大值时才更改种子。因此,如果标识值已经像@MatthisKohli 的情况一样大,则必须调用显式的重新种子。
【解决方案2】:
DBCC CHECKIDENT('databasename.dbo.tablename', RESEED, number)

如果 number=0,那么在下一次插入中,自动增量字段将包含值 1

如果 number=101,那么在下一次插入中,自动增量字段将包含值 102


一些附加信息...可能对您有用

在上述查询中提供自动增量 number 之前,您必须确保现有表的自动增量列包含值小于number

要从表(table1)中获取列(column_name)的最大值,可以使用以下查询

 SELECT MAX(column_name) FROM table1

【讨论】:

  • 你不能不包括种子数,它会使用最大值吗?例如 DBCC CHECKIDENT('databasename.dbo.tablename') 并且 NOT 包括 , RESEED, number?
【解决方案3】:

半白痴:

declare @max int;  
select @max = max(key) from table;  
dbcc checkident(table,reseed,@max)

http://sqlserverplanet.com/tsql/using-dbcc-checkident-to-reseed-a-table-after-delete

【讨论】:

  • "DBCC CHECKIDENT (table_name)" 做同样的事情(可能没有竞争条件)
  • @user1027167 文档说“如果表的当前标识值小于存储在标识列中的最大标识值”;这不包括删除数据后的清理(重新使用 id - 通常是一个坏主意)。在 SQL 2008 上验证
  • 最好的系统和自动答案。太棒了!
【解决方案4】:

如果你使用 MySQL,试试这个:

ALTER TABLE tablename AUTO_INCREMENT = 1

【讨论】:

  • 这是 MySQL 的答案。 OP 正在询问 MSSQL。
  • 可能,但答案仍然可以帮助像我这样的其他人。
【解决方案5】:

我想通了。它是:

 DBCC CHECKIDENT ('tablename', RESEED, newseed)

【讨论】:

  • 你如何获得“newseed”?不是我不知道,只是一个完整的答案可以解释这一点。
【解决方案6】:

删除并重新设置数据库中的所有表。

    USE [DatabaseName]
    EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"       -- Disable All the constraints
    EXEC sp_MSForEachTable "DELETE FROM ?"    -- Delete All the Table data
    Exec sp_MSforeachtable 'DBCC CHECKIDENT(''?'', RESEED, 0)' -- Reseed All the table to 0
    Exec sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"  -- Enable All  the constraints back

-- You may ignore the errors that shows the table without Auto increment field.

【讨论】:

    【解决方案7】:

    根据接受的答案,对于那些遇到类似问题的人,具有完整的架构资格:

    ([MyDataBase].[MySchemaName].[MyTable])... 导致错误,您需要在该数据库的上下文中

    也就是说,下面会抛出错误:

    DBCC CHECKIDENT ([MyDataBase].[MySchemaName].[MyTable], RESEED, 0)
    

    用单引号将完全限定的表名括起来:

    DBCC CHECKIDENT ('[MyDataBase].[MySchemaName].[MyTable]', RESEED, 0)
    

    【讨论】:

      【解决方案8】:

      几个答案建议使用类似这样的语句:

      DBCC CHECKIDENT (mytable, RESEED, 0)
      

      但是 OP 说“删除了一些记录”,可能不是全部,所以值 0 并不总是正确的。另一个答案建议自动找到最大当前值并重新设置该值,但如果表中没有记录,则会遇到麻烦,因此 max() 将返回 NULL。建议使用简单的评论

      DBCC CHECKIDENT (mytable)
      

      重置该值,但另一条评论正确地指出这只会将值增加到表中已有的最大值;如果它已经高于表中的最大值,这不会减少值,这是 OP 想要做的。

      更好的解决方案结合了这些想法。第一个 CHECKIDENT 将值重置为 0,第二个将其重置为当前表中的最大值,以防表中有记录:

      DBCC CHECKIDENT (mytable, RESEED, 0)
      DBCC CHECKIDENT (mytable)
      

      正如多个 cmets 所指出的,请确保其他表中没有指向已删除记录的外键。否则,这些外键将指向您在重新设置表后创建的记录,这几乎肯定不是您的想法。

      【讨论】:

      • 第二个命令需要是 DBCC CHECKIDENT (mytable, RESEED)
      • @statler 根据docs.microsoft.com/en-us/sql/t-sql/database-console-commands/… 命令“DBCC CHECKIDENT (table_name)”和“DBCC CHECKIDENT (table_name, RESEED)”做同样的事情。请参阅备注部分中的第二个条目。
      • 显然,但不幸的是,如果您在数据库上运行没有 RESEED 的命令,它就不起作用。无法解释文档。只是。 - 至少在我使用的数据库上。
      【解决方案9】:

      我想添加这个答案,因为DBCC CHECKIDENT-approach 会在您对表使用架构时产生问题。使用它来确定:

      DECLARE @Table AS NVARCHAR(500) = 'myschema.mytable';
      DBCC CHECKIDENT (@Table, RESEED, 0);
      

      如果要检查操作是否成功,请使用

      SELECT IDENT_CURRENT(@Table);
      

      在上面的例子中应该输出0

      【讨论】:

        【解决方案10】:

        您一般不希望这样做。 Reseed 会造成数据完整性问题。它实际上仅适用于您要清除所有测试数据并重新开始的开发系统。如果尚未删除所有相关记录,则不应在生产系统上使用它(并非每个应具有外键关系的表!)。这样做可能会造成混乱,尤其是如果您打算在每次删除后定期执行此操作。担心身份字段值的差距是个坏主意。

        【讨论】:

        • 我不会一直使用它,它只是在测试数据库上。
        【解决方案11】:

        将数据库中的每个键重置为从最后一个最高键的最大值自动递增:

        Exec sp_MSforeachtable 'DBCC CHECKIDENT(''?'', RESEED, 0)'
        
        Exec sp_MSforeachtable 'DBCC CHECKIDENT(''?'', RESEED)'
        

        【讨论】:

        • 这是一种在所有表上调用 DBCC 命令的巧妙方法。不幸的是,在没有指定种子值的情况下,CHECKINDENT 命令对我没有任何作用,只是确定了最大值。 @user423430 仍然是为我恢复丢失的身份值的唯一答案。如果我能执行那整套命令,那就太好了。我试过了,但是存储过程似乎不接受多个命令。
        【解决方案12】:

        这个怎么样?

        ALTER TABLE `table_name`
          MODIFY `id` int(12) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;
        

        这是一种将自动增量更改为 0 或您想要的任何数字的快速简单的方法。我通过导出数据库并自己阅读代码来解决这个问题。

        你也可以这样写,使其成为单行解决方案:

        ALTER TABLE `table_name` MODIFY `id` int(12) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;
        

        【讨论】:

        • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation would greatly improve its long-term value 通过展示为什么这是一个很好的解决问题的方法,并将使其对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
        【解决方案13】:

        如果您只是想重置主键/序列以在 SQL 服务器中以您想要的序列开头,这就是解决方案 -

        ID:

        99 100 101 1200 1201...

        1. 删除 ID >= 1200 的行。(如果您有与这些相关联的外键约束,必须处理或删除这些约束才能删除它。)
        2. 现在您要确定自己知道 MAX ID 以确保:

        将@max_id 声明为 int = (SELECT MAX(your_column_name) FROM 你的表)+1;

        (注意:+1 表示在最大值之后开始 ID 序列)

        1. 重新启动您的序列:

        exec('alter sequence your_column_name 重新启动 ' + @max_id);

        (注意:with 后面的空格是必须的) 现在新记录将以 102 作为 ID 开头。

        【讨论】:

          猜你喜欢
          • 2017-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-30
          • 2019-12-04
          • 2017-11-16
          • 1970-01-01
          相关资源
          最近更新 更多