Reseed an Identity Column in SQL Server: SQL in Sixty Seconds #051

To reseed an identity column, run DBCC CHECKIDENT with the RESEED option and the value you want. Episode 51 of SQL in Sixty Seconds shows the command. It changes the value the column uses next. It does not renumber the rows that already exist.

Gouache painting of a row of unmarked wooden pegs with a movable starting stop and a small vermilion marker.

How an Identity Column Hands Out Numbers

An identity column has a seed and an increment. The seed is the first number, and the increment is the step between numbers. The table remembers the last number it handed out. That memory is the value you change when you reseed an identity column.

Reseed an Identity Column Step by Step

First read the current value. NORESEED reports it and changes nothing. Then reseed. The script below uses a temporary table, so it leaves nothing behind. Run the whole script in one query window.

CREATE TABLE #IdentityDemo
(
    ID int IDENTITY(1,1) PRIMARY KEY,
    Col1 varchar(100)
);
INSERT INTO #IdentityDemo (Col1)
VALUES ('First'), ('Second'), ('Third'), ('Fourth'), ('Fifth');
DBCC CHECKIDENT ('#IdentityDemo', NORESEED);
DBCC CHECKIDENT ('#IdentityDemo', RESEED, 11);
INSERT INTO #IdentityDemo (Col1)
VALUES ('First'), ('Second'), ('Third'), ('Fourth'), ('Fifth');
SELECT ID, Col1 FROM #IdentityDemo ORDER BY ID;
DROP TABLE #IdentityDemo;

The first DBCC message reads current identity value ‘5’, current column value ‘5’. The final query returns ten rows.

IDCol1
1First
2Second
3Third
4Fourth
5Fifth
12First
13Second
14Third
15Fourth
16Fifth

The old rows kept IDs 1 to 5. The new rows start at 12, which is the reseed value 11 plus the increment of 1.

Quick reference card: Reseed an Identity Column in SQL Server: SQL in Sixty Seconds #051

An Empty Table Behaves Differently

The next value depends on how the table became empty. I filled two tables with three rows each. I emptied one with DELETE and the other with TRUNCATE TABLE, then reseeded both to 100. A third table never had a row and was reseeded to 1000.

How the table was emptiedReseed valueFirst new ID
DELETE100101
TRUNCATE TABLE100100
Never had rows10001000

DELETE leaves the old counter in place, so the next ID is the reseed value plus the increment. TRUNCATE resets the counter to the seed. A table with no history uses the reseed value itself.

What Goes Wrong When You Reseed Too Low

I reseeded a table that held IDs 1, 2 and 3 back to 1. The next insert needed ID 2, and the primary key refused it with Msg 2627. The message ends with The duplicate key value is (2). The failed insert still used up the value 2.

Without a primary key or unique index, the same steps run without any error. That table ended up with two rows that had ID 2. Duplicate IDs are worse than the gaps you wanted to remove.

Read the Current Value Without DBCC

You do not need DBCC to look at the counter. IDENT_CURRENT returns the last value generated for a table. The view sys.identity_columns shows the seed, the increment and the last value together.

SELECT IDENT_CURRENT('dbo.IdentityDemo') AS LastValue;
SELECT name, seed_value, increment_value, last_value
FROM sys.identity_columns
WHERE object_id = OBJECT_ID('dbo.IdentityDemo');

For the table in the first example, both queries returned 16. After a TRUNCATE, last_value in sys.identity_columns is NULL until the first insert.

Find a Safe Value Before You Reseed

On a table that holds data, look at the largest ID first. Reseed to that number or higher. The next ID is then above every ID in the table, unless something inserts explicit IDs later.

SELECT MAX(ID) AS LargestId FROM dbo.IdentityDemo;

Reseed Only When You Know Why

Gaps in an identity column are normal. Rolled-back inserts and deletes leave them. SQL Server 2017 and later also has the IDENTITY_CACHE setting, which is on by default (the value reads 1). Documentation names it as a reason numbers can skip after a restart. Reseeding closes none of these gaps.

A plain DBCC CHECKIDENT ('table') only moves the value up. In my test the current value was 4 and the largest ID was 2. The command changed nothing, and the next insert got ID 5. To go lower, name the value with RESEED.

Good reasons to reseed are test data you reload and a table you emptied on purpose. On a table with data, check the maximum ID first and never go below it.

Related Reading

Reseeding is not a way to renumber a table, it is a way to choose the next value.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Identity, SQL in Sixty Seconds, SQL Scripts, SQL Server DBCC
Previous Post
Remove a Cached Connection in SSMS: SQL in Sixty Seconds #049
Next Post
ANSI_NULLS Puzzle and NULL in SQL Server: SQL in Sixty Seconds #052

Related Posts

12 Comments. Leave new

  • Sanjay Monpara
    May 8, 2013 3:43 pm

    In one of our software we have given feature of purge database at UI side,
    in this case I have used reseed option with value 0.

    Reply
  • I HAVE TO SELECT A VARCHAR COLUMN HAVING LENGTH 4 OR 5 CHARACTERS I HAVE TO PUT ‘000’ (ZEROS) BEFORE THIS COLUMN IF IT’S LENGTH IS 4 THEN I HAVE TO PUT 4 ZEROS BEFORE IT’S AND IF IT’S LENGTH IS 5 THEN I HAVE TO PUT 3 ZEROS I HAVE TO MAKE TOTAL LENGTH EQUAL TO 8
    LIKE THIS
    SELECT POSTCODE,
    CASE LEN(POSTCODE) < 8 THEN
    WHILE LEN(POSTOCDE) < 8 LOOP
    POSTCODE = '0'+POSTCODE
    END LOOP
    END
    FROM ABCTABLE.

    please resolve this asap

    Reply
    • @Rao Mohsin

      Try this

      DECLARE @var VARCHAR(10)
      SET @var = ‘123456’
      SET @var = RIGHT(REPLICATE(‘0’, 8) + LTRIM(RTRIM(@var)), 8)

      SELECT @var

      Reply
  • Neil Macehiter
    June 18, 2013 6:06 pm

    In response to your question: “However, there is one question which keeps on ringing in my mind that is why would anyone need to reseed identity”.

    Reseeding an identity can sometimes be necessary in certain replication scenarios with automatic identity range management.

    Reply
    • I reseed the database when I am merging two database into one database.
      this allows the users to keep on adding row while I merge the data into the “HOLE” I created by reseeding 100k above the current seed.

      Reply
  • or in a scenario where so many rows are deleted and inserted, that eventually you reach the maximum of the identity column’s data type, while there are substantially less records in the table than is possible to hold by the identity column. In these scenarios working through foreign key properties gets a little tiresome when reseeding though!

    Reply
  • Thank you very much…this is not the first time I have learnt from your blog…just the first time I am leaving a message. Your work is excellent and you have helped me very many times. Thank you.

    Reply
  • This is the script which i have written ,i hope it may help to some one

    Declare @id int
    Declare @count int
    Declare @name varchar(100)
    Declare @countercheck int
    Declare @temp table (id int identity(1,1) ,name varchar(200))
    Declare @sqlquery NVARCHAR(500)
    Declare @ParmDefinition NVARCHAR(500)
    Declare @column_name varchar(50)
    Declare @maxvalue int
    set @id=0
    set @count=0
    set @countercheck=0

    Insert into @temp(name)
    select name=table_name from information_schema.tables where OBJECTPROPERTY( object_id(table_name), ‘TableHasIdentity’)=1 order by table_name desc
    set @countercheck=@@rowcount

    While @count<@countercheck
    Begin
    select top 1 @name=name ,@id =id from @temp order by name desc
    select @column_name=name from sys.columns where object_id=object_id(@name) and is_identity=1
    set @sqlquery = 'select @maxvalue = max(['+@column_name+']) from '+ @name
    set @ParmDefinition=' @maxvalue int OUTPUT ,@column_name varchar(50),@name varchar(100)'
    Execute sp_executesql @sqlquery,@ParmDefinition, @maxvalue OUTPUT ,@column_name ,@name
    set @maxvalue =isnull(@maxvalue,0)
    dbcc checkident(@name,reseed ,@maxvalue)
    Delete from @temp where id=@id
    set @count=@count+1
    End

    Reply
  • Jairo A. Elias
    May 14, 2015 6:55 pm

    rakesh, thank you a lot.. It really help me.

    Reply
  • Why would I need to reseed? In my case there is a bulk insert several times a day of almost a million rows. After they are processed, the table data is deleted. The identity column is int, so there can 8500 bulk inserts be done, then the max value for int is reached. Now I can drop the table and recreate it or just reseed the identity.

    Nils

    Reply
  • Correction: it’s half a million rows, not a million.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.