3

How can I modify table and set identity on PK column using T-SQL?

thanks for help

gruber
  • 28,739
  • 35
  • 124
  • 216
  • possible duplicate of [How to change programmatically non-identity column to identity one?](http://stackoverflow.com/questions/756354/how-to-change-programmatically-non-identity-column-to-identity-one) – Mikael Eriksson Mar 03 '11 at 13:52

6 Answers6

3

You can't modify an existing column to have the IDENTITY "property" - you have to:

  • create a new table with the same structure (but with IDENTITY set up),
  • turn on IDENTITY_INSERT for this new table,
  • insert rows from the old table into the new table,
  • drop the old table, and,
  • rename the new table to have the old table name.

If there are foreign keys involved, you need to fix those up also.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • You can actually do it by starting up the instance in single user mode and modifying the system tables. Annoying that there is no safe/supported way of updating this metadata in current versions. – Martin Smith Mar 03 '11 at 13:46
  • @Martin - Interesting, but would you ever recommend someone doing that? – Damien_The_Unbeliever Mar 03 '11 at 13:47
  • @Martin - this seems like something that RedGate would have made a tool for at some point... – JNK Mar 03 '11 at 13:47
  • @Damien - Absolutely not unless they were just doing it out of curiosity on a test database. – Martin Smith Mar 03 '11 at 13:48
  • [There is a way of doing this on SQL Server 2008](http://stackoverflow.com/questions/6084572/how-to-set-auto-increment-after-creating-a-table-without-any-data-loss/6086661#6086661) – Martin Smith May 23 '11 at 07:35
  • @Martin - Am I being dense - isn't what you're linking to just an actual coded expansion of the bullet points above? There still isn't a way to tell SQL Server "Please turn on `IDENTITY()` on this column", is there? – Damien_The_Unbeliever May 23 '11 at 07:40
  • @Damien - There is no movement of rows. It is a metadata only operation. It runs more or less instantly except for `DBCC CHECKIDENT('dbo.tblFoo')` which seems to still read every data page. – Martin Smith May 23 '11 at 07:41
  • @Martin - ah, so it's the `ALTER TABLE ... SWITCH` that's the magic new bit. Grand. I'll keep that in mind for the future – Damien_The_Unbeliever May 23 '11 at 07:43
  • And now I've got rid of `DBCC CHECKIDENT` it is more or less instant. – Martin Smith May 23 '11 at 08:13
3

The problem with most solutions to this question is that they require either adding a new column to the table or completely rebuilding the table.

Both can require large amounts of locking and logging activity which I have always found annoying as this is a metadata only change and shouldn't necessitate touching the data pages at all (Indeed it is possible to update the metadata directly by starting the instance in single user mode and messing around with some columns in sys.syscolpars but this is undocumented/unsupported.)

However the workaround posted on this connect item shows a completely supported way of making this into a metadata only change using ALTER TABLE...SWITCH (credit SQLKiwi)

Example code.

Set up test table with no identity column.

CREATE TABLE dbo.tblFoo 
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)


INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2

Alter it to have an identity column (more or less instant).

BEGIN TRY;
    BEGIN TRANSACTION;

    /*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
      set the correct seed in the table definition instead*/
    DECLARE @TableScript nvarchar(max)
    SELECT @TableScript = 
    '
    CREATE TABLE dbo.Destination(
        bar INT IDENTITY(' + 
                     CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1)  PRIMARY KEY,
        filler CHAR(8000),
        filler2 CHAR(49)
        )

        ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
    '       
    FROM dbo.tblFoo
    WITH (TABLOCKX,HOLDLOCK)

    EXEC(@TableScript)


    DROP TABLE dbo.tblFoo;

    EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';


    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
    PRINT ERROR_MESSAGE();
END CATCH;

Test the result.

INSERT INTO dbo.tblFoo (filler,filler2) 
OUTPUT inserted.*
VALUES ('foo','bar')

Gives

bar         filler    filler2
----------- --------- ---------
10001       foo       bar      

Clean up

DROP TABLE dbo.tblFoo
Community
  • 1
  • 1
Martin Smith
  • 438,706
  • 87
  • 741
  • 845
1

Is it the answer you are looking for?

DBCC CHECKIDENT( 
    'DBName.dbo.TableName'
    ,RESEED --[, new_reseed_value ]
)

Example use:

DBCC CHECKIDENT( 
    'DBName.dbo.TableName'
)

Checking identity information: current identity value '1', current column value '1211031236'. DBCC execution completed. If DBCC printed error messages, contact your system administrator.

DBCC CHECKIDENT( 
    'DBName.dbo.TableName'
    ,RESEED --[, new_reseed_value ]
)

Checking identity information: current identity value '1211031236', current column value '1211031236'. DBCC execution completed. If DBCC printed error messages, contact your system administrator.

0

In fact, you can modify the IDENTITY on a column. Please read through this article http://www.sqlmag.com/article/tsql3/adding-the-identity-property-to-an-existing-column.aspx

It will need a lot more code than ALTER TABLE tab ALTER COLUMN col SET IDENTITY, though

Steven Ryssaert
  • 1,989
  • 15
  • 25
  • yes, you can do this through Enterprise Manager or SSMS - but what it actually does "behind the scenes" is exactly what I've described above. – Damien_The_Unbeliever Mar 03 '11 at 13:32
  • It's probably also not the best thing to reference a 10 year old article referring to software that is 2 versions older than the one the OP is asking about... – JNK Mar 03 '11 at 13:41
  • I thought newer versions of SQL Server were backwards compatible. Maybe i was mistaken. – Steven Ryssaert Mar 03 '11 at 13:43
  • Moreover, SQL syntax is far older than SQL Server 2000. Still, it is daily used in new queries. Does it make it less accurate because it's old ? – Steven Ryssaert Mar 03 '11 at 13:50
  • 1
    I'm not sure why folks are in such a huff over your recommendation. The tools in SSMS make this stuff a whole lot easier and safer than most homegrown tools. All the methods shown, so far, also don't take into account rebuilding the PK, FK's, Triggers, related views, etc, etc, etc. Your answer is actually the best answer so far as I'm concerned. – Jeff Moden Mar 07 '11 at 04:17
0

You need to use the ALTER TABLE command - always test first in dev or pre-production!

The example G seems closest to your requirement:

CREATE TABLE dbo.doc_exe ( column_a INT CONSTRAINT column_a_un UNIQUE) ; GO ALTER TABLE dbo.doc_exe ADD

-- Add a PRIMARY KEY identity column. column_b INT IDENTITY CONSTRAINT column_b_pk PRIMARY KEY,

See http://msdn.microsoft.com/en-us/library/ms190273.aspx

Peter Schofield
  • 939
  • 7
  • 13
0

Since you can only ignore identity columns for insert, not for update, you'll need an intermediate table. Here's an example:

create table TestTable (pk int constraint PK_TestTable primary key, 
    name varchar(30))
create table TestTable2 (pk int constraint PK_TestTable identity primary key, 
    name varchar(30))
set identity_insert TestTable2 on
insert TestTable2 (pk, name) select pk, name from TestTable
set identity_insert TestTable2 off
drop table TestTable
exec sp_rename 'TestTable2', 'TestTable'
Andomar
  • 232,371
  • 49
  • 380
  • 404