973

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.

dakab
  • 5,379
  • 9
  • 43
  • 67
xorpower
  • 17,975
  • 51
  • 129
  • 180
  • 7
    "in SQL Azure" - "each table has to have an primary key" - true - "and Identity Defined" - false. Identity and primary key are orthogonal concepts. An identity column doesn't have to be the PK of a table. A primary key doesn't have to be an identity column. – Damien_The_Unbeliever Feb 17 '14 at 08:54
  • 1
    OK. My concept could be wrong. But now I have defined the table structure with PK and Identity Seed. If I have to delete some rows, how could I reset Identity Seed in a correct numerical ascending order – xorpower Feb 17 '14 at 08:57
  • 40
    I would always argue that if you care about the actual numerical values generated in an identity column, you're misusing them. All you should care about with an identity column is that it automatically generates unique values (yay!) and that you can store these values in a numerical column (this bit is only relevant for declaring columns to hold these values). You shouldn't be showing them to anyone, so it shouldn't matter what values they take on. – Damien_The_Unbeliever Feb 17 '14 at 08:59
  • you can use dbcc check identify as other mentioned but please note that primary key is not mandatory for sql db v12 – Satya_MSFT Jan 05 '16 at 16:36
  • 3
    @Damien_The_Unbeliever just because one wants to reset id column doesn't mean that they are showing it to end user. if it wasn't needed, it wouldn't be possible to do it anyways. – Burak Karakuş Mar 18 '21 at 15:03

25 Answers25

1518

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.

Petr Abdulin
  • 33,883
  • 9
  • 62
  • 96
  • 3
    It appears that `DBCC CHECKIDENT` is supported as of the upcoming release (V12 / Sterling): http://azure.microsoft.com/en-us/documentation/articles/sql-database-preview-whats-new/ Though, for this particular situation, I would still recommend [TRUNCATE TABLE](http://stackoverflow.com/questions/21824478/reset-identity-seed-after-deleting-records-in-sql-server/27322209#27322209) :) – Solomon Rutzky Jan 09 '15 at 15:58
  • 3
    It didn't work for me until the "GO" was in another line. – mrówa Dec 03 '15 at 13:50
  • 1
    The syntax is getting flagged because of the GO keyword in the same line, I don't know why. Can you move it down a line. I copied and pasted this line 50 times and now I have to go back and fix it. – AnotherDeveloper Mar 04 '16 at 17:58
  • 1
    truncate table won't work if table is referenced (this actually became my problem). I recommend deleting table data then run "DBCC CHECKIDENT ('[TestTable]', RESEED, 0);" +1 for your comment dude! – jace May 05 '17 at 03:44
  • 22
    Worked perfectly for me. It's worth pointing out that when re-seeding a table, if you want to reseed so that your first record is ID 1 then the reseed command must reseed to 0, so that the next record is ID 1. – Mike Upjohn Aug 07 '17 at 09:59
  • `DBCC CHECKIDENT ('[TestTable]', RESEED, 1);` will replicate the default behaviour of SQL Server (ids start at 1 not 0). – voidstate Oct 19 '17 at 11:48
  • @voidstate added edit on your comment. Seems that your comment is not entirely correct. – Petr Abdulin Oct 23 '17 at 05:57
  • I just confirmed that the same is true of SQL Server Express 2014, and probably all other editions of SQL Server 2014, too. Seed with one increment less than the value that you want applied to the next insert. – David A. Gray Nov 14 '17 at 05:01
  • is it possible to do this with a table variable, e.g. @myTable? doesn't seem to be working :/ – mdegges Feb 16 '18 at 07:31
  • 2
    @DavidA.Gray , Petr, and others: Yes, the documentation was both misleading (due to missing a key scenario) and incorrect (due to there actually _not_ being any variation in behavior between versions). I wrote a post about what the documentation said, showed 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)?](https://sqlquantumleap.com/2019/01/31/how-does-dbcc-checkident-really-work-when-resetting-the-identity-seed-reseed/). I also fixed a typo in Example C. – Solomon Rutzky Apr 10 '19 at 02:46
  • Is there any associated performance penalty for using this command? – Agustin Garzon Apr 24 '19 at 19:44
  • 1
    *Very Important*: if your reseeded table contains records and you reseeded to a number lower that the first record left, when your table insertions reach the first record left before, your new inserts will not work till they surpass the last record! – sdlins Dec 27 '19 at 23:27
  • Please also read @abdul's downvoted answer which contains an important note that your initial insert may (or may not) have the *same* value as your seed value, or be pre-incremented (which is what you will be expecting). Not ony does it depend on whether truncation took place, but also whether the table has ever had rows prior to the reseed. So your reseed initial behaviour depends on previous usage, not just the value you set [3rd remark in https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkident-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15 ) – simon coleman Jan 16 '20 at 15:18
  • This stop the order for example u stil could end up with eronous ids eg 1 3 6 – c-sharp-and-swiftui-devni Jul 20 '20 at 22:16
301
DBCC CHECKIDENT ('TestTable', RESEED, 0)
GO

Where 0 is identity Start value

Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
anil shah
  • 3,079
  • 2
  • 12
  • 4
  • 32
    If the table is empty, such as if you just called `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](https://msdn.microsoft.com/en-us/library/ms176057.aspx) – kjbartel Jan 28 '15 at 08:04
  • 7
    @kjbartel , Anil, and others: it's not as simple as just "if the table is empty". The documentation was missing the case for when the table is empty due to `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)?](https://sqlquantumleap.com/2019/01/31/how-does-dbcc-checkident-really-work-when-resetting-the-identity-seed-reseed/). – Solomon Rutzky Apr 10 '19 at 02:51
174

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.

Mike G
  • 4,232
  • 9
  • 40
  • 66
Atal Kishore
  • 4,480
  • 3
  • 18
  • 27
  • 7
    This is the only answer which works 100% of the time – Reversed Engineer Oct 17 '18 at 15:38
  • 9
    A little bit shorter: `declare @max int select @max=ISNULL(max([Id]),0) from [TestTable]; DBCC CHECKIDENT ('[TestTable]', RESEED, @max );` – Guillermo Prandi Feb 08 '19 at 17:49
  • 7
    As reported in the [doc](https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-checkident-transact-sql?view=sql-server-ver15#exceptions) the same result can be achieved using only CHECKIDENT: _Execute DBCC CHECKIDENT (table_name, RESEED,new_reseed_value) with new_reseed_value set to a very low value, and then run DBCC CHECKIDENT (table_name, RESEED) to correct the value._ – jacktric Sep 19 '20 at 16:28
115

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.

Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • 17
    While more efficient under the correct circumstances, this is not always an option. Truncate will not execute on a table that has a FK defined against it. Even when there are no dependent records, truncate will fail if the constraint exists. Also truncate requires ALTER permissions where Delete only needs DELETE. – Rozwel Jan 09 '15 at 13:29
  • 4
    @Rozwel True, but I had already qualified my answer stating that proper permissions need to be in place. Also, the question specifically states that there are no FKs. However, for the sake of clarity, I updated to specify the "no FK" restriction. Thanks for pointing that out. – Solomon Rutzky Jan 09 '15 at 15:54
  • 2
    only quibble is that any FK will block truncate. It is possible (though unusual) to have a FK against a unique constraint that is not part of the PK or identity columns. – Rozwel Jan 09 '15 at 18:51
  • 1
    @Rozwel Again true, but it seems reasonable to assume from the question that there are no unique constraints given that the PK only exists due to the O.P.'s understanding (correct or not) that it is required by Azure SQL Database. Regardless, I am all for reducing ambiguity so I have updated again. Thanks. – Solomon Rutzky Jan 10 '15 at 17:55
  • It's not all that unusual to have a foreign key on a table, and the presence of ANY foreign key prohibits TRUNCATE TABLE. I just discovered this the hard way earlier today when I tried to run TRUNCATE TABLE on a table that has a foreign key that is enforced against two other columns in the table and a unique index in the foreign table. – David A. Gray Nov 14 '17 at 05:06
  • I was here, searching for this specific answer. Yes, I am aware that the ident is meaningless in any specific order, and as long as it is unique that is all we want it for. However, given the amount of 'pre go live' testing in the production environment, then deleting of the records produced, my nice neat system is starting at 3000 something, and that jarrs me deep in my soul. Natural work will mess with the ident going forward, and I am at peace with that, but I can not tolerate the 3000 jump on the first day of production - it hurts me deep inside..... – Awk Sod Mar 29 '21 at 18:35
73

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.

Samuel Rondeau-Millaire
  • 1,100
  • 2
  • 13
  • 24
Mikael Engver
  • 4,634
  • 4
  • 46
  • 53
  • [sqlserver 2008r2 dbcc](http://msdn.microsoft.com/en-us/library/ms188796%28v=sql.105%29.aspx) for [checkident](http://msdn.microsoft.com/en-us/library/ms176057%28v=sql.105%29.aspx) – stackuser83 Dec 03 '14 at 23:13
25

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

RealSollyM
  • 1,530
  • 1
  • 22
  • 35
  • 1
    Unfortunately that's not true. Just checked that for MS SQL 2014 server. – alehro Sep 08 '15 at 11:52
  • 2
    Actually, it is true for SQL 2014. I have just tested it and it worked for me. – Daniel Dyson Sep 16 '15 at 02:19
  • 2
    This works inconsistently for me on SQL 2012. Sometimes it uses the next available one as I would have expected, sometimes it seems to get stuck on an old value from the table. Specifying the seed alwasy works. – Dan Field Oct 15 '15 at 13:01
  • Doesn't work for me on SQL 2016 - it just leaves the identity seed as-is. It may have worked correctly for me one time, but it might also have been my finger trouble. Can't get it to work again – Reversed Engineer Oct 17 '18 at 15:38
  • 1
    The message indicates success, `Checking identity information: current identity value '[incorrect seed]', current column value '[correct seed]'.`, but upon new inserts it's still using the incorrect seed. – Denziloe Feb 21 '19 at 14:40
  • @Denziloe same for me – NicuVlad Sep 26 '22 at 07:41
12

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

Rich Benner
  • 7,873
  • 9
  • 33
  • 39
jacob
  • 145
  • 1
  • 2
  • 3
    DBCC CHECKIDENT ('[TestTable]', RESEED) is not reseeding to next available value – Atal Kishore Aug 23 '16 at 07:13
  • This is the method used by [RedGate Data Compare](https://www.red-gate.com/products/sql-development/sql-data-compare/index) when the option "Reseed identity columns" is turned on. I've tested it extensively (I mean in SQL code, not in the RedGate tool), and it works reliably. (I have no relation to RedGate other than being an occasional user of their trial versions) – Reversed Engineer Feb 24 '20 at 09:24
12

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
  • 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)

Mario Varchmin
  • 3,704
  • 4
  • 18
  • 33
Trent
  • 121
  • 1
  • 2
9

@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.

epic
  • 91
  • 1
  • 1
  • DBCC CHECKIDENT is only functional after deletion. You might as well use truncate. However if you need the rest of the data dont use it. Also truncate does not give a record count of records deleted. – user763539 Jan 31 '17 at 16:39
9

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.

d219
  • 2,707
  • 5
  • 31
  • 36
Dyna Dave
  • 149
  • 1
  • 5
6

you can CHECKIDENT To Reset Seed

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

Example

 DBCC CHECKIDENT ('TAble', reseed,0)

-- Example Query

You can to insert the basic data with the following codes

first create one table after insert data to table

step to step i show data and Remove data for Show Details for understand Code

Result code : Create Table with rest seed Id I used dmv sys.identity_columns that table has identity


--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

First check data if Table has not data use seed table

if Table has data use use Max id

after change seed with 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
abolfazl sadeghi
  • 2,277
  • 2
  • 12
  • 20
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 21 '23 at 01:26
5

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)
;
Chris Mack
  • 5,148
  • 2
  • 12
  • 29
4

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
  • 3
    This is not entirely correct: the SET IDENTITY_INSERT is in the wrong place. It doesn't go around the TRUNCATE, it goes around the INSERT INTO (hence the identity_**INSERT**). Also, this is to be used _only_ when data needs to be kept, else it is very inefficient compared to just running the single TRUNCATE statement. – Solomon Rutzky Dec 05 '14 at 18:05
4

Reset identity column with new id...

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

DBCC CHECKIDENT ('[TestTable]', RESEED,@MAX)
eathan
  • 33
  • 1
  • 6
Mukesh Pandey
  • 139
  • 2
  • 1
4

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.

KimvdLinde
  • 587
  • 8
  • 19
3

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.

Ben Thul
  • 31,080
  • 4
  • 45
  • 68
  • 16
    That's true for a production environment, but while developing I like to remember that certain entities have a certain Id, which are populated from a seeding script. It makes it much easier to navigate through the database while in development. – Francois Botha Oct 22 '14 at 13:18
  • 11
    Answers such as this are completely theoretical and rarely do they comply with real world needs. How about instead of brainwashing people with your dogma, you answer the OP question... – Serj Sagan Mar 26 '15 at 17:16
  • 1
    Cool story, bro. My contention is this: if you want to specify the value for a column, don't choose a property on the column that makes doing that difficult. The code smell is this: if every time you insert a record into a table you specify a value for the identity column, you don't have an identity column. The whole point of identity is to have the server create a value for you. So if you override that ever time, you've gained nothing for a non-zero cost. Also, good work on the ad hominem argument. – Ben Thul Mar 26 '15 at 17:29
  • 6
    I certainly agree with your contention. Looking at face value, the OP is certainly doing it wrong, but perhaps there is a deeper need not stated in the post that the OP did not think was relevant to get his question answered. Hence answer the question, and give "do's and don'ts" advice as part of the answer. By the way, I never attacked your character... ad hominem means I called you stupid or something... – Serj Sagan Mar 26 '15 at 18:04
  • This answer caused me to add a new column separate from the Primary Key Identity field for my data needs, thus eliminating my need to reset the identity seed forevermore in my case. I did, however, have to add a unique constraint to my new column so that I could use a foreign key against it the way I had been using the PK identity field. – Mikhael Loo Feb 17 '16 at 17:43
  • 3
    While certainly true in most cases, there exist circumstances in which it is legitimate to re-seed a table. For example, I am working on a greenfield project that must start from a point certain to account for existing rows in the predecessor that it is replacing. Reseeding during development is a legitimate use case, IMO. – David A. Gray Nov 14 '17 at 05:11
  • 1
    I agree. In development, you may have millions of test records in a DB with identities also in the millions - after doing thousands of tests. Before going to production (and real data), it is nice to be able to reset the identity down to lower numbers (for looks or even something like matching order numbers ) – MC9000 Dec 27 '18 at 07:57
1
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.

Bimzee
  • 1,138
  • 12
  • 15
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.

boggy
  • 3,674
  • 3
  • 33
  • 56
1

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.

Ali Sufyan
  • 94
  • 1
  • 3
1

Use this sp for all tables:

reseed 'youtable'

after delete a record (in a trigger p.e.)

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)
R.Alonso
  • 989
  • 1
  • 8
  • 9
0

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
Fandango68
  • 4,461
  • 4
  • 39
  • 74
0

It seems like the majority of replies here assumes that the table is empty and the Identity value needs to be reset. However, how I read the question is that @xorpower now has a table with records 1, 2, 3, 5, 6, 7, 12, 13, 14 etc...and wants a method to get that back to a contiguous list. (1, 2, 3, 4, 5, 6 , 7 , 8, 9 etc...)

cf But since I have to delete some records from the table, where some is the magic word here IMHO.

AFAIK there is no such a thing in MSSQL; worst case you can indeed dump the existing records table into a new table and go from there. The question to me to is also: why would you want to do that? And is an IDENTITY column then the best approach?

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: Yes, I know this is an old question, but given it's high points count it still shows up on top for similar questions and since nobody mentioned SWITCH yet it seemed worth adding.

deroby
  • 5,902
  • 2
  • 19
  • 33
0

Hello this stored procedure DELETE ALL ROWS of a table and check whether has identity column in the table ,it will be reseed .

**** CAUTION : ALL ROWS WILL BE DELETED . *****

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
Simas Joneliunas
  • 2,890
  • 20
  • 28
  • 35
Abolfazl
  • 1
  • 1
-2

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.

  • 4
    Sounds to me like the idea is to only delete _some_ records. – Drumbeg Jan 05 '16 at 08:23
  • 7
    This is just plain wrong - It is not ALWAYS better to use truncate and, in fact, is only better in some, very limited and specific scenarios. Heaven forbid someone were to follow your advice and then need to rollback. – Thronk Feb 11 '16 at 19:13
  • 1
    @Thronk Why are you implying that `TRUNCATE` would prevent `ROLLBACK` from behaving as expected? ROLLBACK still rolls-back. Even if the DB is set to `BULK_LOGGED`. – Solomon Rutzky Sep 05 '17 at 18:28
  • 2
    TRUNCATE is DDL operation and it is not logged in log file. Unless it is part of transaction (not mentioned anywhere in the question or in this answer). Whenever anyone says something is ALWAYS true, it's a pretty safe bet they are wrong. – Thronk Sep 07 '17 at 03:37
  • This is the *only* answer that notes there is a difference in the RESEED behaviour depending on whether the sequence was previously used or not. A reseed of the same value across multiple *empty* tables, where some tables were previously populated, will result in *different* initial values for the first record inserted into each table. – simon coleman Jan 16 '20 at 15:13
-5

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 >>

slfan
  • 8,950
  • 115
  • 65
  • 78
Pratik Patel
  • 151
  • 1
  • 3