Reordering Identity primary key in sql server

2019-02-17 04:56发布

问题:

Yes i am very well aware the consequences. But i just want to reorder them. Start from 1 to end.

How do I go about reordering the keys using a single query ?

It is clustered primary key index

Reordering like

First record Id 1 
second record Id 2

The primary key is Int

回答1:

  1. Drop PK constraint
  2. Drop Identity column
  3. Re-create Identity Column
  4. Re-Create PK
USE Test
go

if(object_id('IdentityTest') Is not null)
drop table IdentityTest

create table IdentityTest
(
Id int identity not null,
Name varchar(5),
constraint pk primary key (Id)
)

set identity_insert dbo.IdentityTest ON
insert into  dbo.IdentityTest (Id,Name) Values(23,'A'),(26,'B'),(34,'C'),(35,'D'),(40,'E')
set identity_insert dbo.IdentityTest OFF



select * from IdentityTest

------------------1. Drop PK constraint ------------------------------------ 
ALTER TABLE [dbo].[IdentityTest] DROP CONSTRAINT [pk]
GO
------------------2. Drop Identity column -----------------------------------
ALTER table dbo.IdentityTest
drop column Id
------------------3. Re-create Identity Column -----------------------------------
ALTER table dbo.IdentityTest
add Id int identity(1,1)
-------------------4. Re-Create PK-----------------------
ALTER TABLE [dbo].[IdentityTest] ADD  CONSTRAINT [pk] PRIMARY KEY CLUSTERED 
(
[Id] ASC
)

--------------------------------------------------------------
insert into  dbo.IdentityTest (Name) Values('F')
select * from IdentityTest


回答2:

IDENTITY columns are not updatable irrespective of SET IDENTITY_INSERT options.

You could create a shadow table with the same definition as the original except for the IDENTITY property. Switch into that (this is a metadata only change with no movement of rows that just affects the table's definition) then update the rows and switch back though.

A full worked example going from a situation with gaps to no gaps is shown below (error handling and transactions are omitted below for brevity).

Demo Scenario

/*Your original table*/
CREATE TABLE YourTable
(
Id INT IDENTITY PRIMARY KEY,
OtherColumns CHAR(100) NULL
)

/*Some dummy data*/
INSERT INTO YourTable (OtherColumns) VALUES ('A'),('B'),('C')

/*Delete a row leaving a gap*/
DELETE FROM YourTable WHERE Id =2 

/*Verify there is a gap*/
SELECT *
FROM YourTable

Remove Gaps

/*Create table with same definition as original but no `IDENTITY`*/
CREATE TABLE ShadowTable
(
Id INT PRIMARY KEY,
OtherColumns CHAR(100)
)

/*1st metadata switch*/
ALTER TABLE YourTable SWITCH TO ShadowTable;

/*Do the update*/  
WITH CTE AS
(
SELECT *,
       ROW_NUMBER() OVER (ORDER BY Id) AS RN
FROM  ShadowTable     
)
UPDATE CTE SET Id = RN

/*Metadata switch back to restore IDENTITY property*/  
ALTER TABLE ShadowTable SWITCH TO YourTable;

/*Remove unneeded table*/
DROP TABLE ShadowTable;

/*No Gaps*/
SELECT *
FROM YourTable


回答3:

I don't think there is any way to do this in a single query. Your best bet is to copy the data to a new table, drop and recreate the original table (or delete the data and reseed the identity) and reinsert the data in the original order using the previous identity as the ordering (but not re-inserting it).



回答4:

CREATE TABLE Table1_Stg (bla bla bla)

INSERT INTO Table1_Stg (Column2, Column3,...) SELECT Column2, Column3,... FROM Table1 ORDER BY Id

Here the Id column is excluded from the SELECT column list.

Or, you can do:

SELECT * INTO Table1_Stg FROM Table1 ORDER BY Id

DROP Table1

sp_rename Table1_stg Table1

Please lookup the usage for sp_rename as I am doing this from memory.

Hope this helps.

EDIT: Please save a script with all your indexes and constraints if any on Table1.

EDIT2: Added second method of creating table and inserting into table.



回答5:

UPDATE tbl SET id = (SELECT COUNT(*) FROM tbl t WHERE t.id <= tbl.id);