I have inserted records into a SQL Server database table. The table had a primary key defined and the auto increment identity seed is set to “Yes”. This is done primarily because in SQL Azure, each table has to have a primary key and identity defined.
But since I have to delete some records from the table, the identity seed for those tables will be disturbed and the index column (which is auto-generated with an increment of 1) will get disturbed.
How can I reset the identity column after I deleted the records so that the column has sequence in ascending numerical order?
The identity column is not used as a foreign key anywhere in database.
The DBCC CHECKIDENT
management command is used to reset identity counter. The command syntax is:
DBCC CHECKIDENT (table_name [, { NORESEED | { RESEED [, new_reseed_value ]}}])
[ WITH NO_INFOMSGS ]
Example:
DBCC CHECKIDENT ('[TestTable]', RESEED, 0);
GO
It was not supported in previous versions of the Azure SQL Database but is supported now.
Thanks to Solomon Rutzky the docs for the command are now fixed.
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO
Where 0 is identity
Start value
TRUNCATE
, then the new seed value should be the value to next use (i.e. 1 not 0). If the table is not empty it will use the new_reseed_value + 1
. MSDN
DELETE
, not TRUNCATE
, in which case it is also new_reseed+value + 1
. I wrote a post about this, showing the actual behavior via some tests, and updated the actual doc (now that we can due to it being on GitHub): How Does DBCC CHECKIDENT Really Work When Resetting the Identity Seed (RESEED)?.
Although most answers are suggesting RESEED to 0, many times we need to just reseed to next Id available
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)
This will check the table and reset to the next ID.
declare @max int select @max=ISNULL(max([Id]),0) from [TestTable]; DBCC CHECKIDENT ('[TestTable]', RESEED, @max );
It should be noted that IF all of the data is being removed from the table via the DELETE
(i.e. no WHERE
clause), then as long as a) permissions allow for it, and b) there are no FKs referencing the table (which appears to be the case here), using TRUNCATE TABLE
would be preferred as it does a more efficient DELETE
and resets the IDENTITY
seed at the same time. The following details are taken from the MSDN page for TRUNCATE TABLE:
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.
So the following:
DELETE FROM [MyTable];
DBCC CHECKIDENT ('[MyTable]', RESEED, 0);
Becomes just:
TRUNCATE TABLE [MyTable];
Please see the TRUNCATE TABLE
documentation (linked above) for additional information on restrictions, etc.
I tried @anil shahs
answer and it reset the identity. But when a new row was inserted it got the identity = 2
. So instead I changed the syntax to:
DELETE FROM [TestTable]
DBCC CHECKIDENT ('[TestTable]', RESEED, 0)
GO
Then the first row will get the identity = 1.
Although most answers are suggesting RESEED
to 0
, and while some see this as a flaw for TRUNCATED
tables, Microsoft has a solution that excludes the ID
DBCC CHECKIDENT ('[TestTable]', RESEED)
This will check the table and reset to the next ID
. This has been available since MS SQL 2005 to current.
https://msdn.microsoft.com/en-us/library/ms176057.aspx
Checking identity information: current identity value '[incorrect seed]', current column value '[correct seed]'.
, but upon new inserts it's still using the incorrect seed.
issuing 2 command can do the trick
DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
the first reset the identity to zero , and the next will set it to the next available value -- jacob
I have just used DBCC CHECKIDENT
successfully
Things to note:
when referencing table name square brackets are not accepted
DBCC CHECKIDENT('TableName',RESEED,n) will reset back to n+1 e.g. DBCC CHECKIDENT('tablename',RESEED,27) will start at 28
e.g. DBCC CHECKIDENT('tablename',RESEED,27) will start at 28
if you are having issues with not setting the new starting id - noting this you could fix this by:
DECLARE @NewId as INT
SET @NewId = (SELECT MAX('TableName')-1 AS ID FROM TableName)
DBCC CHECKIDENT('TableName',RESEED,@MaxId)
@jacob
DBCC CHECKIDENT ('[TestTable]', RESEED,0)
DBCC CHECKIDENT ('[TestTable]', RESEED)
Worked for me, I just had to clear all entries first from the table, then added the above in a trigger point after delete. Now whenever i delete an entry is taken from there.
Truncate
table is preferred because it clears the records, resets the counter and reclaims the disk space.
Delete
and CheckIdent
should be used only where foreign keys prevent you from truncating.
Reset identity column with new id...
DECLARE @MAX INT
SELECT @MAX=ISNULL(MAX(Id),0) FROM [TestTable]
DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
I use the following script to do this. There's only one scenario in which it will produce an "error", which is if you have deleted all rows from the table, and IDENT_CURRENT
is currently set to 1, i.e. there was only one row in the table to begin with.
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)
;
This is a common question and the answer is always the same: don't do it. Identity values should be treated as arbitrary and, as such, there is no "correct" order.
Run this script to reset the identity column. You will need to make two changes. Replace tableXYZ with whatever table you need to update. Also, the name of the identity column needs dropped from the temp table. This was instantaneous on a table with 35,000 rows & 3 columns. Obviously, backup the table and first try this in a test environment.
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
I've been trying to get this done for a large number of tables during development, and this works as a charm.
DBCC CHECKIDENT('www.newsType', RESEED, 1);
DBCC CHECKIDENT('www.newsType', RESEED);
So, you first force it to be set to 1, then you set it to the highest index of the rows present in the table. Quick and easy rest of the idex.
DBCC CHECKIDENT (<TableName>, reseed, 0)
This will set the current identity value to 0.
On inserting the next value, the identity value get incremented to 1.
Use this stored procedure:
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'
Just revisiting my answer. I came across a weird behaviour in sql server 2008 r2 that you should be aware of.
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
The first select produces 0, Item 1
.
The second one produces 1, Item 1
. If you execute the reset right after the table is created the next value is 0. Honestly, I am not surprised Microsoft cannot get this stuff right. I discovered it because I have a script file that populates reference tables that I sometimes run after I re-create tables and sometimes when the tables are already created.
For a complete DELETE rows and reset the IDENTITY count, I use this (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
Reseeding to 0 is not very practical unless you are cleaning up the table as a whole.
other wise the answer given by Anthony Raymond is perfect. Get the max of identity column first, then seed it with max.
Its always better to use TRUNCATE when possible instead of deleting all records as it doesn't use log space also.
In case we need delete and need to reset the seed, always remember that if table was never populated and you used DBCC CHECKIDENT('tablenem',RESEED,0)
then first record will get identity = 0 as stated on msdn documentation
In your case only rebuild the index and don't worry about losing the series of identity as this is a common scenario.
TRUNCATE
would prevent ROLLBACK
from behaving as expected? ROLLBACK still rolls-back. Even if the DB is set to BULK_LOGGED
.
First : Identity Specification Just : "No" >> Save Database Execute Project
After then : Identity Specification Just : "YES" >> Save Database Execute Project
Your Database ID, PK Start from 1 >>
Success story sharing
DBCC CHECKIDENT
is supported as of the upcoming release (V12 / Sterling): azure.microsoft.com/en-us/documentation/articles/… Though, for this particular situation, I would still recommend TRUNCATE TABLE :)