删除SQL Server中的记录后重置标识种子

xor*_*wer 628 sql database sql-server sql-server-2008 azure-sql-database

我已将记录插入SQL Server数据库表.该表定义了主键,并且自动增量标识种子设置为"是".这主要是因为在SQL Azure中,每个表都必须定义主键和标识.

但是由于我必须从表中删除一些记录,这些表的标识种子将受到干扰,并且索引列(自动生成的增量为1)将受到干扰.

删除记录后,如何重置标识列,以使列按数字顺序递增?

标识列不用作数据库中任何位置的外键.

Pet*_*lin 1023

DBCC CHECKIDENT管理命令用来复位身份计数器.命令语法是:

DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}])
[ WITH NO_INFOMSGS ]
Run Code Online (Sandbox Code Playgroud)

例:

DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO
Run Code Online (Sandbox Code Playgroud)

以前版本的Azure SQL数据库不支持它,但现在支持.


请注意,根据文档new_reseed_value,SQL Server版本的参数是不同的:

如果表中存在行,则使用new_reseed_value值插入下一行.在SQL Server 2008 R2及更早版本中,插入的下一行使用new_reseed_value +当前增量值.

但是,我发现这些信息具有误导性(实际上只是错误的),因为观察到的行为表明至少SQL Server 2012仍然使用new_reseed_value +当前的增量值逻辑.微软甚至与自己Example C在同一页面上发现的内容相矛盾:

C.将当前标识值强制为新值

以下示例强制将AddressType表中的AddressTypeID列中的当前标识值设置为10.因为该表具有现有行,所以插入的下一行将使用11作为值,即,为其定义的新当前增量值列值加1.

USE AdventureWorks2012;  
GO  
DBCC CHECKIDENT ('Person.AddressType', RESEED, 10);  
GO
Run Code Online (Sandbox Code Playgroud)

尽管如此,这都为新的SQL Server版本留下了不同行为的选项.我想在确保微软在自己的文档中清理内容之前,唯一可以确定的方法是在使用前进行实际测试.

  • 语法将是... DBCC CHECKIDENT('[TestTable]',RESEED,0)GO (22认同)
  • 直到“GO”在另一行中才对我有用。 (3认同)
  • 为我工作完美.值得注意的是,在重新播种表格时,如果要重新播种以使第一条记录为ID 1,则重新设定的命令必须重新设定为0,以便下一条记录为ID 1. (3认同)
  • 在即将发布的版本(V12/Sterling)中似乎支持`DBCC CHECKIDENT`:http://azure.microsoft.com/en-us/documentation/articles/sql-database-preview-whats-new/虽然,对于这种特殊情况,我仍然建议[TRUNCATE TABLE](http://stackoverflow.com/questions/21824478/reset-identity-seed-after-deleting-records-in-sql-server/27322209#27322209):) (2认同)
  • @DavidA.Gray、Petr 和其他人:是的,该文档既具有误导性(由于缺少关键场景)又不正确(由于版本之间的行为实际上没有任何变化)。我写了一篇关于文档内容的文章,通过一些测试展示了实际行为,并更新了实际文档(现在我们可以,因为它位于 GitHub 上):[重置身份种子时 DBCC CHECKIDENT 是如何工作的(RESEED) )?](https://sqlquantumleap.com/2019/01/31/how-does-dbcc-checkident-really-work-when-resetting-the-identity-seed-reseed/)。我还修正了示例 C 中的一个拼写错误。 (2认同)

小智 201

DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO
Run Code Online (Sandbox Code Playgroud)

其中0是identity起始值

  • 如果表是空的,例如你刚刚调用`TRUNCATE`,那么新的种子值应该是下次使用的值(即1不是0).如果表不为空,则使用`new_reseed_value + 1`.[MSDN](https://msdn.microsoft.com/en-us/library/ms176057.aspx) (12认同)
  • @kjbartel、Anil 和其他人:这并不像“如果桌子是空的”那么简单。由于“DELETE”,而不是“TRUNCATE”,文档缺少表为空的情况,在这种情况下,它也是“new_reseed+value + 1”。我写了一篇关于这个的帖子,通过一些测试展示了实际行为,并更新了实际文档(现在我们可以因为它在 GitHub 上):[DBCC CHECKIDENT 在重置身份种子 (RESEED) 时如何真正工作?] (https://sqlquantumleap.com/2019/01/31/how-does-dbcc-checkident-really-work-when-resetting-the-identity-seed-reseed/)。 (4认同)

Sol*_*zky 81

应该注意的是,如果通过(即无子句)从表中删除所有数据,则只要a)权限允许它,并且b)没有引用该表的FK(似乎是在这种情况下,使用将是优选的,因为它更有效并且同时重置种子.以下详细信息来自TRUNCATE TABLE的MSDN页面:DELETEWHERETRUNCATE TABLEDELETE IDENTITY

与DELETE语句相比,TRUNCATE TABLE具有以下优点:

  • 使用较少的事务日志空间.

    DELETE语句一次删除一行,并在事务日志中为每个已删除的行记录一个条目.TRUNCATE TABLE通过释放用于存储表数据的数据页来删除数据,并仅在事务日志中记录页面解除分配.

  • 通常使用较少的锁.

    使用行锁执行DELETE语句时,表中的每一行都被锁定以进行删除.TRUNCATE TABLE总是锁定表(包括模式(SCH-M)锁)和页面,但不是每行.

  • 毫无例外,表格中留有零页面.

    执行DELETE语句后,表仍可以包含空页.例如,如果没有至少一个独占(LCK_M_X)表锁,则无法释放堆中的空页.如果删除操作不使用表锁,则表(堆)将包含许多空页.对于索引,删除操作可以留下空页,尽管这些页面将通过后台清理过程快速释放.

如果表包含标识列,则该列的计数器将重置为为该列定义的种子值.如果未定义种子,则使用默认值1.要保留身份计数器,请改用DELETE.

所以以下内容:

DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);
Run Code Online (Sandbox Code Playgroud)

变得公正:

TRUNCATE TABLE [MyTable];
Run Code Online (Sandbox Code Playgroud)

TRUNCATE TABLE有关限制等的其他信息,请参阅文档(上面链接).

  • 虽然在正确的情况下更有效,但这并不总是一种选择.Truncate不会在具有针对它定义的FK的表上执行.即使没有依赖记录,如果约束存在,truncate也会失败.truncate也需要ALTER权限,其中Delete只需要删除. (6认同)
  • @Rozwel是的,但我已经确定了我的答案,说明需要适当的权限.此外,该问题明确指出没有FK.但是,为了清楚起见,我更新了指定"无FK"限制.感谢您指出了这一点. (3认同)
  • 唯一的问题是任何 FK 都会阻止截断。有可能(尽管不寻常)针对不属于 PK 或标识列的唯一约束使用 FK。 (2认同)

Ata*_*ore 74

虽然大多数答案建议重新设置为0,但很多时候我们需要重新调整到下一个可用的ID

declare @max int
select @max=max([Id])from [TestTable]
if @max IS NULL   //check when max is returned as null
  SET @max = 0
DBCC CHECKIDENT ('[TestTable]', RESEED,@max)
Run Code Online (Sandbox Code Playgroud)

这将检查表并重置为下一个ID.

  • 如 [doc](https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkident-transact-sql?view=sql-server-ver15# 中所述异常)仅使用 CHECKIDENT 即可获得相同的结果:_执行 DBCC CHECKIDENT (table_name, RESEED,new_reseed_value) 并将 new_reseed_value 设置为非常低的值,然后运行 ​​DBCC CHECKIDENT (table_name, RESEED) 来更正该值。_ (8认同)
  • 这是唯一一个100%有效的答案 (2认同)
  • 简短一点:`声明@max int从[TestTable]中选择@ max = ISNULL(max([Id]),0); DBCC CHECKIDENT('[TestTable]',RESEED,@max);` (2认同)

Mik*_*ver 61

我试过@anil shahs回答并重置身份.但是当插入一个新行时,它就得到了identity = 2.所以我改为将语法改为:

DELETE FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO
Run Code Online (Sandbox Code Playgroud)

然后第一行将获得identity = 1.


Sol*_*lyM 15

虽然大多数的回答所提出的建议RESEED0,虽然一些人认为这是一个缺陷TRUNCATED表,微软已经排除了一个解决方案ID

DBCC CHECKIDENT ('[TestTable]', RESEED)
Run Code Online (Sandbox Code Playgroud)

这将检查表并重置为下一个ID.从MS SQL 2005到现在,这已经可用.

https://msdn.microsoft.com/en-us/library/ms176057.aspx

  • 实际上,对于 SQL 2014 来说确实如此。我刚刚测试过它,它对我有用。 (2认同)
  • 这在SQL 2012上对我来说不一致.有时它会像我期望的那样使用下一个可用的,有时似乎卡在表中的旧值上.指定种子alwasy工作. (2认同)

小智 13

我刚刚使用DBCC CHECKIDENT成功

注意事项:

  • 引用表名时不接受方括号
  • DBCC CHECKIDENT('TableName',RESEED,n)将重置回 n+1
    • 例如DBCC CHECKIDENT('tablename',RESEED,27)将于 28 开始
  • 如果您在未设置新的起始 ID 时遇到问题 - 注意到这一点,您可以通过以下方式解决此问题:
    DECLARE @NewId as INT  
    SET @NewId =  (SELECT MAX('TableName')-1  AS ID FROM TableName)
    DBCC CHECKIDENT('TableName',RESEED,@MaxId)

Run Code Online (Sandbox Code Playgroud)


abo*_*ghi 10

您可以 CHECKIDENT 重置种子

DBCC CHECKIDENT
 (
    table_name
        [ , { NORESEED | { RESEED [ , new_reseed_value ] } } ]
)
[ WITH NO_INFOMSGS ]

Run Code Online (Sandbox Code Playgroud)

例子

 DBCC CHECKIDENT ('TAble', reseed,0)
Run Code Online (Sandbox Code Playgroud)

-- 查询示例

您可以使用以下代码插入基本数据

向表中插入数据后先创建一张表

一步一步我显示数据并删除数据以显示详细信息以了解代码

结果代码:使用其余种子 ID 创建表我使用 dmv sys.identity_columns 该表具有标识


--Create Table 
DROP TABLE IF EXISTS  ExampleTable
create table ExampleTable (Id Bigint identity(1,1), Name nvarchar(10))

--Insert to ExampleTable and Delete and Show identity 
insert into ExampleTable (Name) 
select 'Test1' as NAme union all select 'Test2' as NAme

select * from ExampleTable

| Id       | Name |
| -------- | -----|
| 1        |Test1 |
| 2        |Test2 |

delete from ExampleTable

insert into ExampleTable (Name) select 'Test3' as NAme

select * from ExampleTable

| Id       | Name |
| -------- | -----|
| 3        |Test3 |

delete from ExampleTable
Run Code Online (Sandbox Code Playgroud)

首先检查数据如果表没有数据则使用种子表

如果表有数据使用则使用 Max id

使用 CHECKIDENT 更改种子后

--Find seedTable
declare @reseed int=0

if(not exists( select top 1 * from ExampleTable))
begin

    
     SELECT 
        @reseed=cast( seed_value as int)
    FROM sys.tables tables 
        JOIN sys.identity_columns identity_columns 
    ON tables.object_id=identity_columns.object_id
    where 
        tables.name='ExampleTable' 
    and OBJECT_SCHEMA_NAME(tables.object_id, db_id())='dbo'
 
      set @reseed=@reseed -1

 end
 else
 begin
   --if Table Has Data and use Max id For  seed
    set @reseed=(select top 1 id from ExampleTable order by id desc)

 end


  DBCC CHECKIDENT ('ExampleTable', reseed,@reseed)


insert into ExampleTable
(Name)
select 'Test4' as NAme


select * from ExampleTable


| Id       | Name |
| -------- | -----|
| 1        |Test4 |
 

GO
Run Code Online (Sandbox Code Playgroud)


小智 7

Truncate table 是首选,因为它清除记录、重置计数器并回收磁盘空间。

Delete并且CheckIdent应该仅在外键阻止您截断的情况下使用。


小智 5

发出2条命令可以解决问题

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
Run Code Online (Sandbox Code Playgroud)

第一个将标识重置为零,下一个将其设置为下一个可用值-jacob

  • DBCC CHECKIDENT('[TestTable]',RESEED)没有重新播种到下一个可用值 (2认同)

小智 5

@jacob

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
Run Code Online (Sandbox Code Playgroud)

为我工作,我只需要先从表中清除所有条目,然后在删除后将其添加到触发点.现在每当我删除一个条目从那里.


小智 5

使用新ID重置身份列...

DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
Run Code Online (Sandbox Code Playgroud)


Chr*_*ack 5

我使用以下脚本来执行此操作。只有一种情况会产生“错误”,即如果您已删除表中的所有行,并且IDENT_CURRENT当前设置为 1,即表中一开始只有一行。

DECLARE @maxID int = (SELECT MAX(ID) FROM dbo.Tbl)
;

IF @maxID IS NULL
    IF (SELECT IDENT_CURRENT('dbo.Tbl')) > 1
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 0)
    ELSE
        DBCC CHECKIDENT ('dbo.Tbl', RESEED, 1)
    ;
ELSE
    DBCC CHECKIDENT ('dbo.Tbl', RESEED, @maxID)
;
Run Code Online (Sandbox Code Playgroud)


Kim*_*nde 5

我一直在尝试在开发过程中为大量表完成此操作,这很有魅力。

DBCC CHECKIDENT('www.newsType', RESEED, 1);
DBCC CHECKIDENT('www.newsType', RESEED);
Run Code Online (Sandbox Code Playgroud)

因此,您首先强制将其设置为 1,然后将其设置为表中存在的行的最高索引。快速轻松地休息。