我已经将记录插入到SQL Server数据库表中。该表定义了一个主键,并且自动递增标识种子被设置为“Yes”。这样做主要是因为在SQL Azure中,每个表都必须定义一个主键和标识。

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

如何在删除记录后重置标识列,使该列具有升序数字顺序?

标识列在数据库中的任何地方都不能用作外键。


DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

其中0是标识起始值


DBCC CHECKIDENT management命令用于重置标识计数器。命令格式为:

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

例子:

DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO

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


多亏了Solomon Rutzky,该命令的文档现在已经修复。


这是一个常见的问题,答案总是一样的:不要这样做。身份值应该被视为任意的,因此,没有“正确”的顺序。


我尝试了@anil shahs的答案,它重置了身份。但是当插入新的行时,它得到了恒等式= 2。所以我把语法改为:

DELETE FROM [TestTable]

DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO

那么第一行将得到恒等式= 1。


运行此脚本重置标识列。您需要做两个更改。用需要更新的表替换tableXYZ。此外,标识列的名称需要从临时表中删除。这在一个有35000行和3列的表上是瞬时的。显然,备份表并首先在测试环境中尝试这一点。


select * 
into #temp
From tableXYZ

set identity_insert tableXYZ ON

truncate table tableXYZ

alter table #temp drop column (nameOfIdentityColumn)

set identity_insert tableXYZ OFF

insert into tableXYZ
select * from #temp

需要注意的是,如果所有的数据都是通过DELETE从表中删除的(即没有WHERE子句),那么只要a)权限允许,b)没有fk引用表(这里似乎就是这种情况),使用TRUNCATE table将是首选,因为它可以更有效地DELETE并同时重置IDENTITY种子。以下细节取自TRUNCATE TABLE的MSDN页面:

Compared to the DELETE statement, TRUNCATE TABLE has the following advantages: Less transaction log space is used. The DELETE statement removes rows one at a time and records an entry in the transaction log for each deleted row. TRUNCATE TABLE removes the data by deallocating the data pages used to store the table data and records only the page deallocations in the transaction log. Fewer locks are typically used. When the DELETE statement is executed using a row lock, each row in the table is locked for deletion. TRUNCATE TABLE always locks the table (including a schema (SCH-M) lock) and page but not each row. Without exception, zero pages are left in the table. After a DELETE statement is executed, the table can still contain empty pages. For example, empty pages in a heap cannot be deallocated without at least an exclusive (LCK_M_X) table lock. If the delete operation does not use a table lock, the table (heap) will contain many empty pages. For indexes, the delete operation can leave empty pages behind, although these pages will be deallocated quickly by a background cleanup process. If the table contains an identity column, the counter for that column is reset to the seed value defined for the column. If no seed was defined, the default value 1 is used. To retain the identity counter, use DELETE instead.

下面是:

DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);

变成:

TRUNCATE TABLE [MyTable];

请参阅TRUNCATE TABLE文档(上面有链接)以获得有关限制等的其他信息。


虽然大多数答案都建议RESEED为0,而且有些人认为这是TRUNCATED表的缺陷,但微软有一个排除ID的解决方案

DBCC CHECKIDENT ('[TestTable]', RESEED)

这将检查表并重置到下一个ID。它从MS SQL 2005到现在都是可用的。

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


在可能的情况下使用TRUNCATE总是比删除所有记录更好,因为它也不使用日志空间。

如果我们需要删除和重置种子,请记住,如果表从未被填充,并且您使用DBCC CHECKIDENT('tablenem',RESEED,0) 那么第一条记录将得到identity = 0 如MSDN文档所述

在您的情况下,只重建索引,而不用担心丢失 级数恒等式这样的情况很常见。


DBCC CHECKIDENT (<TableName>, reseed, 0)

这将把当前标识值设置为0。

在插入下一个值时,标识值将增加到1。


虽然大多数答案都建议RESEED到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)

这将检查表并重置到下一个ID。


发出2号命令就可以做到这一点

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

第一个将标识重置为零,下一个将其设置为下一个可用值 ——雅各


@jacob

DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)

对我来说,我只需要先从表中清除所有条目,然后在删除后的触发点中添加上面的条目。现在每当我删除一个条目时,它就从那里被取出。


用新id重置标识列

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

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)

截断表是首选,因为它可以清除记录,重置计数器并回收磁盘空间。

Delete和CheckIdent应该只在外键阻止截断的情况下使用。


第一个:标识规范只是:“No”>>保存数据库执行项目

之后:身份规范只是:“是”>>保存数据库执行项目

您的数据库ID, PK从1 >>开始


使用这个存储过程:

IF (object_id('[dbo].[pResetIdentityField]') IS NULL)
  BEGIN
    EXEC('CREATE PROCEDURE [dbo].[pResetIdentityField] AS SELECT 1 FROM DUMMY');
  END
GO

SET  ANSI_NULLS ON
GO
SET  QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[pResetIdentityField]
  @pSchemaName NVARCHAR(1000)
, @pTableName NVARCHAR(1000) AS
DECLARE @max   INT;
DECLARE @fullTableName   NVARCHAR(2000) = @pSchemaName + '.' + @pTableName;

DECLARE @identityColumn   NVARCHAR(1000);

SELECT @identityColumn = c.[name]
FROM sys.tables t
     INNER JOIN sys.schemas s ON t.[schema_id] = s.[schema_id]
     INNER JOIN sys.columns c ON c.[object_id] = t.[object_id]
WHERE     c.is_identity = 1
      AND t.name = @pTableName
      AND s.[name] = @pSchemaName

IF @identityColumn IS NULL
  BEGIN
    RAISERROR(
      'One of the following is true: 1. the table you specified doesn''t have an identity field, 2. you specified an invalid schema, 3. you specified an invalid table'
    , 16
    , 1);
    RETURN;
  END;

DECLARE @sqlString   NVARCHAR(MAX) = N'SELECT @maxOut = max(' + @identityColumn + ') FROM ' + @fullTableName;

EXECUTE sp_executesql @stmt = @sqlString, @params = N'@maxOut int OUTPUT', @maxOut = @max OUTPUT

IF @max IS NULL
  SET @max = 0

print(@max)

DBCC CHECKIDENT (@fullTableName, RESEED, @max)
go

--exec pResetIdentityField 'dbo', 'Table'

回顾一下我的答案。我在sql server 2008 r2中遇到了一个奇怪的行为,你应该知道。

drop table test01

create table test01 (Id int identity(1,1), descr nvarchar(10))

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

delete from test01

execute pResetIdentityField 'dbo', 'test01'

insert into test01 (descr) values('Item 1')

select * from test01

第一个选择生成0,Item 1。

第二个生成1,项目1。如果在表创建后立即执行重置,则下一个值为0。老实说,我并不惊讶微软不能把这些东西做好。我发现它是因为我有一个填充引用表的脚本文件,有时在重新创建表后运行,有时在已经创建表时运行。


对于一个完整的DELETE行和重置IDENTITY计数,我使用这个(SQL Server 2008 R2)

USE mydb

-- ##################################################################################################################
-- DANGEROUS!!!! USE WITH CARE
-- ##################################################################################################################

DECLARE
  db_cursor CURSOR FOR
    SELECT TABLE_NAME
      FROM INFORMATION_SCHEMA.TABLES
     WHERE TABLE_TYPE = 'BASE TABLE'
       AND TABLE_CATALOG = 'mydb'

DECLARE @tblname VARCHAR(50)
SET @tblname = ''

OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname

WHILE @@FETCH_STATUS = 0
BEGIN
  IF CHARINDEX('mycommonwordforalltablesIwanttodothisto', @tblname) > 0
    BEGIN
      EXEC('DELETE FROM ' + @tblname)
      DBCC CHECKIDENT (@tblname, RESEED, 0)
    END

  FETCH NEXT FROM db_cursor INTO @tblname
END

CLOSE db_cursor
DEALLOCATE db_cursor
GO

我使用下面的脚本来做到这一点。只有一种情况下,它会产生一个“错误”,即如果你已经删除了表中的所有行,而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)
;

重新播种到0是不太实际的,除非您要清理整个表。

除此之外,安东尼·雷蒙德给出的答案是完美的。首先得到单位列的最大值,然后用max作为种子。


在开发过程中,我一直试图为大量的表完成这项工作,这非常有效。

DBCC CHECKIDENT('www.newsType', RESEED, 1);
DBCC CHECKIDENT('www.newsType', RESEED);

因此,您首先强制将其设置为1,然后将其设置为表中当前行的最高索引。快速和简单的休息idex。


我刚刚成功地使用了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)


这里的大多数回复似乎都假定表为空,Identity值需要重置。 然而,我如何阅读这个问题是@xorpower现在有一个记录1,2,3,5,6,7,12,13,14等的表…并需要一个方法将其返回到一个连续列表。(1、2、3、4、5、6、7、8、9等…)

但是由于我必须从表中删除一些记录, 恕我直言,这里有个神奇的词。

AFAIK在MSSQL中没有这样的东西;在最坏的情况下,您确实可以将现有的记录表转储到一个新表中,然后从那里开始。我的问题是:你为什么要这样做?IDENTITY列是最好的方法吗?

Anyway,the solutions provided here that do care about existing data are mostly about copying everything in a temp-table, TRUNCATEing the existing table; reseeding the table and then copying everything back again. I'm sure that works but if you have a lot of data then this is a pretty heavy operation. Personally I would rather go with creating an identical table, copying the data in that new table (maybe in batches?) and then finally SWITCHing the data to the original table and dropping the newly created table again. You're likely to need to do a CHECKIDENT after the SWITCH. This way you only need to move the data from one table to another once. To save space you could even DELETE the relevant records from the original table after a batch is copied.

PS:是的,我知道这是一个老问题,但考虑到它的高得分,它仍然出现在类似问题的顶部,因为没有人提到SWITCH,它似乎值得添加。


删除一个表的所有行,检查表中是否有标识列,将被重新播种。

****警告:所有行将被删除。*****

Create PROCEDURE ClearTableData 
    @TableName varchar(100)
AS
    EXEC ('ALTER TABLE '+@TableName+'  NOCHECK CONSTRAINT ALL ') 
    BEGIN TRY  
        EXEC ('Truncate Table'+@TableName )
        PRINT @TableName +' rows have trancated '
    END TRY  
    BEGIN CATCH  
        EXEC ('Delete From '+@TableName )
        PRINT @TableName +' rows have deleted '
    END CATCH  
    
    IF (OBJECTPROPERTY(OBJECT_ID(@TableName), 'TableHasIdentity'))  = 1 
            DBCC CHECKIDENT (@TableName, RESEED, 0) 

    EXEC ('ALTER TABLE '+@TableName+'  CHECK CONSTRAINT ALL ') 

GO

对所有表使用这个sp:

补播“youtable”

在删除一条记录后(在触发程序中)

ALTER PROCEDURE [dbo].[RESEED](@Tabla nvarchar(100))

as

-- ********************* CREAR ESTA FUNCIÓN PRIMERO *******************************
/*
create function  dbo.FN_EsIdentidad(@Tabla nvarchar(100), @Campo nvarchar(100))
    returns int
    as
    begin
        return columnproperty ( object_id ( @Tabla  ), @Campo , 'IsIdentity')
    end 
GO
************************************************************************************
*/


declare @CampoIdentidad nvarchar(100)

    SELECT @CampoIdentidad  = Column_Name
        --,dbo.FN_EsIdentidad(Table_Name, Column_name) as EsIdentidad,
        --table_name, column_name 
        FROM information_schema.columns
        where dbo.FN_EsIdentidad(Table_Name, Column_name) = 1 
        and Table_Name=@Tabla


declare @Sql nvarchar(max)
declare @OutPutNum int
set @Sql = 'Select MAX(' + @CampoIdentidad + ') From ' + @Tabla
--select @CampoIdentidad


set @sql = 'Select @ValorOut=max(' + @CampoIdentidad + ') From ' + @Tabla 
declare @ParamDefinition nvarchar(max)
SET @ParamDefinition = '@ValorOut int OUTPUT'

EXECUTE sp_executesql  
    @SQL 
    ,@ParamDefinition  
    ,@ValorOut = @OutPutNum OUTPUT;  

--select @OutPutNum
set @OutPutNum  = coalesce(@OutPutNum ,0)
DBCC CHECKIDENT (@Tabla, RESEED, @OutputNum)

你可以CHECKIDENT重置种子

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

例子

 DBCC CHECKIDENT ('TAble', reseed,0)

-- 示例查询

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

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

步骤到步骤i显示数据和删除数据显示细节理解代码

结果代码:创建带有rest种子Id的表 我用的是车管局系统。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

首次检查数据 如果表中没有数据使用种子表

如果表中有数据,使用最大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