SQL Reset Identity ID in already populated table - sql

hey all. I have a table in my DB that has about a thousand records in it. I would like to reset the identity column so that all of the ID's are sequential again. I was looking at this but I'm ASSuming that it only works on an empty table
Current Table
ID | Name
1 Joe
2 Phil
5 Jan
88 Rob
Desired Table
ID | Name
1 Joe
2 Phil
3 Jan
4 Rob
Thanks in advance

The easiest way would be to make a copy of the current table, fix up any parentid issues, drop it and then rename the new one.
You could also temporarily remove the IDENTITY and try the folowing:
;WITH TBL AS
(
SELECT *, ROW_NUMBER(ORDER BY ID) AS RN
FROM CURRENT_TABLE
)
UPDATE TBL
SET ID = RN
Or, if you don't care about the order of the records, this
DECLARE INT #id;
SET #id = 0;
UPDATE CURRENT_TABLE
SET #id = ID = #id + 1;

one way, wrap this in a transaction
select id,name into #temp from YourTable
truncate table YourTable
insert YourTable (name)
select name from #temp

Quick solution would be to:
create a new table with the same schema
copy the old table to the new one (except for the identity column)
delete the old table
rename the new table

Because you have foreign keys in the same table (per your comment), you will need to preserve the mapping from old to new somewhere and re-instate the foreign keys to match the new identities.
There are a number of approaches for doing this, but I would strongly question the need to update your primary keys, especially since you already have foreign keys referencing them, and it's just a surrogate key. It's not like you are changing your surrogate key to a GUID or something special.

Here's how I reset identity fields. The CTE (Common Table Expression) above version is overkill. Just use the current Row Number to update the identity column using a simple update statement with a join:
UPDATE [YourTable] SET ID = rn.RowNumber FROM [YourTable]
JOIN (SELECT ID, ROW_NUMBER() OVER (ORDER BY ID) AS RowNumber
FROM [YourTable]) rn ON rn.ID = [YourTable].ID
This statement may be refactored to be even simpler. If so, I would love to see the simpler version.
I hope this helps someone.

Use DBCC CHECKIDENT. the table doesn't need to be empty:
DBCC CHECKIDENT ( table_name, NORESEED)
Current identity value is not reset.
DBCC CHECKIDENT returns the current
identity value and the current maximum
value of the identity column. If the
two values are not the same, you
should reset the identity value to
avoid potential errors or gaps in the
sequence of values.
DBCC CHECKIDENT ( table_name ) or DBCC CHECKIDENT ( table_name, RESEED )
If the current identity value for a
table is less than the maximum
identity value stored in the identity
column, it is reset using the maximum
value in the identity column.
DBCC CHECKIDENT ( table_name, RESEED, new_reseed_value )
Current identity value is set to the
new_reseed_value. If no rows have been
inserted into the table since the
table was created, or if all rows have
been removed by using the TRUNCATE
TABLE statement, the first row
inserted after you run DBCC CHECKIDENT
uses new_reseed_value as the identity.
Otherwise, the next row inserted uses
new_reseed_value + the current
increment value.
If the table is not empty, setting the
identity value to a number less than
the maximum value in the identity
column can result in one of the
following conditions:
If a PRIMARY KEY or UNIQUE constraint exists on the identity
column, error message 2627 will be
generated on later insert operations
into the table because the generated
identity value will conflict with
existing values.
If a PRIMARY KEY or UNIQUE constraint does not exist, later
insert operations will result in
duplicate identity values.

Related

Reset identity seed after in SQL Server in table filled with records

I have a Table called Person, this table is non-empty and it's filled with records ( more than 1000 rows )
How can I reset the identity seed of this table?
Id
PersonName
154
Alice
155
John
The query was executed, but the table still has the identity
use [MyDatabase]
DBCC CHECKIDENT ('dbo.Person', RESEED, 0)
GO
Expected result of the table after executing the previous query :
Id
PersonName
1
Alice
2
John
The problem is your understanding; the code is very likely working exactly as it is supposed to, and as I demonstrated.. RESEED resets the value of the next IDENTITY generated, it doesn't change any of the existing values.
Take SQL similar to what I gave in the comments:
CREATE TABLE dbo.Person (ID int IDENTITY(1,1), AbligatoryColumn char(1));
GO
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT N1.N
FROM N N1, N N2, N N3)
INSERT INTO dbo.Person (AbligatoryColumn)
SELECT 'a'
FROM Tally;
GO
SELECT TOP (5) *
FROM dbo.Person
ORDER BY ID ASC;
If you run this you get the follow results:
ID AbligatoryColumn
----------- ----------------
1 a
2 a
3 a
4 a
5 a
Now, let's RESEED the table, and INSERT another row:
DBCC CHECKIDENT ('dbo.Person', RESEED, 0)
GO
INSERT INTO dbo.Person
DEFAULT VALUES;
GO
SELECT TOP (5) *
FROM dbo.Person
ORDER BY ID ASC;
This gives the following data set:
ID AbligatoryColumn
----------- ----------------
1 a
1 NULL
2 a
3 a
4 a
Notice that there are 2 rows where ID has a value of 1. This is because the new row we inserted has used thenew seed, so the next value generated was 1 (as when you RESEED you are defining the last value used, not the next value to be).
Note that you can't UPDATE the value of an IDENTITY, so if we tried the following you would get an error:
UPDATE dbo.Person
SET ID = ID + 1000
WHERE AbligatoryColumn = 'a';
Cannot update identity column 'ID'.
The real question why do you want to change the value? An IDENTITY is just an arbitrary value, it's value doesn't matter.
If you "must" (and I would suggest you don't need to) you would need to CREATE a new table, INSERT the data from your existing table into it (likely with IDENTITY_INSERT enabled) and then DROP your old table, and rename the new one. If you have any foreign key constraints pointing to your current table, you'll need to DROP all of these, and I really hope you have any data referencing the existing ID values, as you'll then need to update all the foreign key values before you recreate the foreign key constraints. As a result your new table would (albeit likely temporarily) need to have both the old and new PK values in separate columns.
So, in truth, leave it as it is; the value of an IDENTITY literally doesn't matter. It's an arbitrary value and it whether the first value starts at 1, 17, or -167 or if there are numbers "missing" is irrelevant to functionality of what IDENTITY is there to achieve; an always ascending value.

Identity specification

I have a problem with identity specification when I create a table in SQL Server 2016.
In column Id I set Identity Increment and Identity Seed equal 1.
Next I add new record to new table.
In column Id show up 2 value. Why? Why not 1 value?
Next drop the first record and add new. In column Id show up 3 value. Why? Why not 1 value.
Next I use command ' update nametable set id=1' and receive answer cannot update identity column Id. Why?
This is probably easier to explain with some code:
CREATE TABLE YourTable (ID int IDENTITY(1,1),
SomeCol varchar(5));
INSERT INTO dbo.YourTable (SomeCol)
VALUES('abc'); --Will get ID 1
INSERT INTO dbo.YourTable (SomeCol)
VALUES('def'),('ghi'); --Will get 2 and 3.
SELECT *
FROM dbo.YourTable;
DELETE FROM dbo.YourTable;
INSERT INTO dbo.YourTable (SomeCol)
VALUES('abc'); --Will get ID 4, because 1-3 have been used. Deleting doesn't let you reuse values.
SELECT *
FROM dbo.YourTable;
DELETE FROM dbo.YourTable;
DBCC CHECKIDENT ('dbo.YourTable', RESEED, 1);
INSERT INTO dbo.YourTable (SomeCol)
VALUES('abc'); --Will get ID 2, as you seeded back to 1; so the NEXT ID is used.
SELECT *
FROM dbo.YourTable;
TRUNCATE TABLE dbo.YourTable;
INSERT INTO dbo.YourTable (SomeCol)
VALUES('abc'); --Will get ID 4, because 1-3 have been used.
SELECT *
FROM dbo.YourTable; --Will get ID 1, as the column was reseed with the TRUNCATE
DROP TABLE dbo.YourTable;
For your specific question on reseeding, the next value after the seed your define is use. The seed you define is the one you are saying was last used. This is covered in the documentation Forcing the current identity value to a new value:
Because the table has existing rows, the next row inserted will use 11
as the value – the new current identity value defined for the column
plus 1 (which is the column's increment value).
The only way to define a table doesn't have existing rows is the TRUNCATE it, which is what I do later on in the above batch (and why 1 is reused).
At the end of the day, the value of your IDENTITY is meaningless other than to provide the row with a single use value (which is not guarenteed to be unique on it's own). Combined with the Primary key/Unique constraints, it makes a good Clustered index candidate, as the next value is always greater than the last used, and values aren't reused.
If having sequential values is important, then what you need to use is a SEQUENCE, not the IDENTITY property. The latter doesn't guarantee uniqueness, or sequential values on it's own (as they could be skipped due to deletes, failed inserts, an unexpected shutdown, etc), but it does guarantee it will not reuse values once they have been (without a RESEED): IDENTITY (Transact-SQL) - Remarks. A SEQUENCE can be used to ensure the values are indeed sequential (apart from due to a DELETE).
Welcome to the forum :)
If you created the table using
Id INT IDENTITY(1,1)
Then the first record inserted will have Id = 1, however, if the insert statement fails or the transaction is rolled back the consumed identity be marked as used (or lost) and the next insert statement will proceed from Id = 2.
Have a look at Microsoft documentation on this topic:
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property?view=sql-server-2017
When deleting inserted rows (which also happens when those inserts are rolled-back in a transaction, by the way), the identity value is not automatically reset. The identity functionality "remembers" its last value.
Gaps in the identity values will also NOT be filled when older records are deleted from the table and new records are inserted into the table.
That's just how identity works. It's a simple and safe mechanism.
If you (occasionally!) want to reset the identity value, you can take a look at DBCC CHECKIDENT. I personally tend to use it like this:
DBCC CHECKIDENT (MyTable, RESEED, 0) WITH NO_INFOMSGS;
DBCC CHECKIDENT (MyTable, RESEED) WITH NO_INFOMSGS;
(I execute both lines, in this order.)
I would advice against this practice in production environments, however.

Updating Identity Column of a table with consecutive numbers through SQL Stored Procedure

After deleting the duplicate records from the table,
I want to update Identity column of a table with consecutive numbering starting with 1. Here is my table details
id(identity(1,1)),
EmployeeID(int),
Punch_Time(datetime),
Deviceid(int)
I need to perform this action through a stored procedure.
When i tried following statement in stored procedure
DECLARE #myVar int
SET #myVar = 0
set identity_insert TempTrans_Raw# ON
UPDATE TempTrans_Raw# SET #myvar = Id = #myVar + 1
set identity_insert TempTrans_Raw# off
gave error like...Cannot update identity column 'Id'
Anyone please suggest how to update Identity column of that table with consecutive numbering starting with 1.
--before running this make sure Foreign key constraints have been removed that reference the ID.
--insert everything into a temp table
SELECT (ColumnList) --except identity column
INTO #tmpYourTable
FROM yourTable
--clear your table
DELETE FROM yourTable
-- reseed identity
DBCC CHECKIDENT('table', RESEED, new reseed value)
--insert back all the values
INSERT INTO yourTable (ColumnList)
SELECT OtherCols FROM #tmpYourTable
--drop the temp table
DROP TABLE #tmpYourTable
GO
The IDENTITY keword is used to generate a key which can be used in combination with the PRIMARY KEY constraint to get a technical key. Such keys are technical, they are used to link table records. They should have no other meaning (such as a sort order). SQL Server does not guarantee the generated IDs to be consecutive. They do guarantee however that you get them in order. (So you might get 1, 2, 4, ..., but never 1, 4, 2, ...)
Here is the documentation for IDENTITY: https://msdn.microsoft.com/de-de/library/ms186775.aspx.
Personally I don't like it to be guaranteed that the generated IDs are in order. A technical ID is supposed to have no meaning other then offering a reference to a record. You can rely on the order, but if order is information you are interested in, you should store that information in my opinion (in form of a timestamp for example).
If you want to have a number telling you that a record is the fifth or sixteenth or whatever record in order, you can get always get that number on the fly using the ROW_NUMBER function. So there is no need to generate and store such consecutive value (which could also be quite troublesome when it comes to concurrent transactions on the table). Here is how to get that number:
select
row_number() over(order by id),
employeeid,
punch_time,
deviceid
from mytable;
Having said all this; it should never be necessary to change an ID. It is a sign for inappropriate table design, if you feel that need.
If you really need sequential numbers, may I suggest that you create a table ("OrderNumbers") with valid numbers, and then make you program pick one row from OrderNumbers when you add a row to yourTable.
If you everything in one transaction (i.e. with Begin Tran and Commit) then you can get one number for one row with no gabs.
You should have either Primary Keys or Unique Keys on both tables on this column to protect against duplicates.
HIH,
Henrik
Check this function: DBCC CHECKIDENT('table', RESEED, new reseed value)

Insert value into an old identity field

I have a table which had an identity column.
for many reasons we had to remove the identity from that column.
I have a system that inserts a value to that table by the old way, passes null for the identity column.
is there a simple way to define identity column to receive a value in case it is passed to it, and if a value of null is passed, to make that table to set a unique value to that field that is not found in that table (act like identity).
What i mean is, if there is value, insert it.
And if the system tries to insert null act like an identity.
Thanks in advance.
A trigger seems like a good choice for this situation, but there are a lot of ways you can handle the situation.
The example below creates an INSTEAD OF insert trigger that gets the columns that were supposed to be inserted, and generates a new value via a function if the ID column is null.
CREATE TRIGGER myTrigger ON myTable
INSTEAD OF INSERT
AS
INSERT INTO myTable (myIDcolumn, anotherColumn)
SELECT COALESCE(myIDColumn, dbo.SomeMethodToCreateID), anotherColumn
FROM inserted
How that SomeTheodToCreateID function is to work is up to you. One thing you could do is change the SELECT to combine max plus row_number:
SELECT (COALESCE(myIDColumn,
(SELECT MAX(myIDColumn) FROM myTable) + ROW_NUMBER() OVER(ORDER BY anotherColumn)
)
...
Try This
DBCC CHECKIDENT ( '[dbo].[Customers]', RESEED, 1 )

SQL Server deleted identity columns

in SQL SERVER 2010, I deleted some columns that made use of identity fields.
I like to insert rows where the identity columns were deleted with the original values but not sure how to do so.
I tried edit but the identity columns were greyed out
UPDATE table
SET IDENTITY_INSERT [YourTableName] ON
--do your update/insert query here
SET IDENTITY_INSERT [YourTableName] OFF
Can you explain why you care whether there are gaps in your identity columns? If you just want some pretty ID number next to a label (and aren't worried about related data in other tables, or whether the 2nd row retains the ID 2 even if ID 1 is deleted), you can always derive these meaningless ID numbers at runtime, e.g.
SELECT col, MeaninglessID = ROW_NUMBER() OVER (ORDER BY col)
FROM dbo.table
ORDER BY col;
You need to reseed the identity:
dbcc checkident (mytable, reseed, 30)