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

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

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

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


当前回答

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

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

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

其他回答

对于一个完整的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

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

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

使用这个存储过程:

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。老实说,我并不惊讶微软不能把这些东西做好。我发现它是因为我有一个填充引用表的脚本文件,有时在重新创建表后运行,有时在已经创建表时运行。

我刚刚成功地使用了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,它似乎值得添加。