我已经将记录插入到SQL Server数据库表中。该表定义了一个主键,并且自动递增标识种子被设置为“Yes”。这样做主要是因为在SQL Azure中,每个表都必须定义一个主键和标识。
但是由于我必须从表中删除一些记录,这些表的标识种子将受到干扰,索引列(自动生成的增量为1)也将受到干扰。
如何在删除记录后重置标识列,使该列具有升序数字顺序?
标识列在数据库中的任何地方都不能用作外键。
我已经将记录插入到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,它似乎值得添加。