Convert an existing Column to Identity - sql

I have a table in SQL Server with bundle of records. I want to convert the ID column which is Primary Key to an identity Column without loss of data. I thought of the following two approaches:
Create a new table with identity & drop the existing table.
Create a new column with identity & drop the existing column.
but it's clear that they can not be implemented because keeping records is my first priority.
Is there another way to do this?

This solution violates your point 2, but there is no other way and I think your aim is to keep the old values, because nothing else makes sense...
You could do the following:
make it possible to insert into identity columns in your table:
set identity_insert YourTable ON
add a new ID column to your table with identity and insert the values from your old columns
turn identity insert off
set identity_insert YourTable OFF
delete old ID column
rename new column to old name
make it to the primary key
The only problem could be that you have your ID column already connected as foreign key to other tables. Then you have a problem with deleting the old column...
In this case you have to drop the foreign key constraints on your ID column after step 3, then do step 4 to 6 and then recreate your foreign key constraints.

As you are using SQL Server 2012, another possible alternative could be to create a sequence object that has a starting value of the highest ID +1 already in your table, then create a default constraint for your column using GET NEXT VALUE FOR and reference your sequence object you just created.

If you have direct access to the Server Database, just go into the design of the table, select the PK column, and change the identity to "Yes". Make sure you set your seed to the max value of that column. The increment is 1 by default. Save the table design and you should be good to go.

Considering the source table isn't too big:
Create new table (with IDENTITY)
Populate new table from existing table (with IDENTITY_INSERT ON)
Drop old table (drop any existing FKs first)
Rename new table to old name (re-establish FKs if needed)
-- Create Sample Existing Table
DROP TABLE IF EXISTS #tblTest
CREATE TABLE #tblTest
(
ID INT NOT NULL
, Val VARCHAR(10) NOT NULL
)
INSERT INTO #tblTest
(
ID
, Val
)
VALUES
(1, 'a')
, (2, 'b')
, (4, 'c')
GO
-- Create and Populate New Table (with IDENTITY_INSERT ON)
DROP TABLE IF EXISTS #tblTestNew
CREATE TABLE #tblTestNew
(
ID INT IDENTITY(1, 1) NOT NULL
, Val VARCHAR(10) NOT NULL
)
SET IDENTITY_INSERT #tblTestNew ON
INSERT INTO #tblTestNew
(
ID
, Val
)
(
SELECT
#tblTest.ID
, #tblTest.Val
FROM
#tblTest
)
SET IDENTITY_INSERT #tblTestNew OFF
GO
-- Rename Existing Table to Old (can use sp_rename instead, but I can't for temp tables)
SELECT * INTO #tblTestOld FROM #tblTest
DROP TABLE #tblTest
GO
-- Rename New Table to Existing (can use sp_rename instead, but I can't for temp tables)
SELECT * INTO #tblTest FROM #tblTestNew
DROP TABLE #tblTestNew
GO
-- Test Inserting new record
INSERT INTO #tblTest (Val)
VALUES ('d')
-- Verify Results
SELECT * FROM #tblTest
EXEC tempdb.sys.sp_help #objname = N'#tblTest'
-- Drop 'Old' Table (when ready)
DROP TABLE IF EXISTS #tblTestOld
-- Cleanup
DROP TABLE IF EXISTS #tblTest
DROP TABLE IF EXISTS #tblTestNew
DROP TABLE IF EXISTS #tblTestOld
If the table is very large, consider the log growth, Recovery Model, possible single-user mode, etc.

create table t1 (col1 int, col2 varchar(10))
insert into t1 values (10, 'olddata')
--add identity col
alter table t1 add col3 int identity(1,1)
GO
--rename or remove old column
alter table t1 drop column col1
--rename new col to old col name
exec sp_rename 't1.col3', 'col1', 'column'
GO
--add new test , review table
insert into t1 values ( 'newdata')
select * from t1

Related

Specify "NEXT VALUE" for INSERT statement using identity column in SQL Server

Consider the following table and SQL from Microsoft's INSERT documentation that deals with IDENTITY columns:
CREATE TABLE dbo.T1 (column_1 int IDENTITY, column_2 VARCHAR(30));
GO
INSERT T1 (column_2) VALUES ('Row #2');
The INSERT statement does not specify column_1 as a column of the table, and SQL Server auto-populates the next value for that identity column. This is the normal way identity columns are handled.
How can I have the same behavior, while also specifying the column name?
For example, I'm looking for something like:
INSERT INTO T1 (column_1, column_2)
VALUES (NEXT VALUE, 'Row #3');
GO
I don't believe NEXT VALUE works here, but is there something that does work? Is there a key token or function that will indicate that the identity column should be used?
Note: the reason I ask is that the framework I'm using requires all columns to be specified in the column list.
If you are on SQL Server 2012 and later, you can use sequence. But you must remove the IDENTITY property from Column1 first. This can only be done by copy-and-rename a new table.
CREATE SEQUENCE Column1_Sequence
AS int
START WITH 0;
CREATE TABLE T1
(
Column1 int DEFAULT (NEXT VALUE FOR Column1_Sequence) PRIMARY KEY
, Column2 nvarchar(30)
)
After that, you can insert data into the table in 2 ways:
INSERT INTO T1 (Column1, Column2)
SELECT NEXT VALUE FOR Column1_Sequence
, 'Row #2'
INSERT INTO T1 (Column2)
SELECT 'Hello world'
Can you set the identity insert on before inserting and then set the identity insert off
You cannot set value for identity column unless you set identity_insert on for this table (one at time). Some examples:
create table #tmp (id int identity(1,1), name varchar(10))
insert #tmp (id,name) values (2,'test')
--error Cannot insert explicit value for identity column in table '#tmp
set identity_insert #tmp on --for one table in DB
insert #tmp (id,name) values (2,'qwas')
select * from #tmp
set identity_insert #tmp off -- good practice
--works
--see current identity value
SELECT IDENT_CURRENT ('#tmp') AS Current_Identity;
--Reset identity value
DBCC CHECKIDENT (#tmp, RESEED, 999)
--next insert will be 1000
Of course, if you reset next identity to a value which conflicts with PK (common usage of identity) you will have Violation of PRIMARY KEY constraint error
I am pretty sure there is no way to do that with SQL Server. Two workarounds that I can think of:
Fix the library if possible.
If the library supports it, you can create a view and INSERT into that instead. For example:
CREATE TABLE MyTable
(
ID INT IDENTITY(1, 1),
SomeColumn VARCHAR(100)
)
GO
CREATE VIEW MyTableView
AS
SELECT SomeColumn
FROM MyTable
GO
INSERT INTO MyTableView (SomeColumn) VALUES ('Test')

How we can add column in sql server with auto generated record insertion number. if Index are defined on that table

My database(SQL server 2008) already having some records and having two sorting index on two columns. I tried to add identity column using following query. But it providing me wrong identity numbers associated with records.
alter table Table_name add RECORD_NUMBER int identity(1,1)
record which inserted first having higher number and record which is inserted last having lower number. and some records are having just opposite numbers. Is it possible to remove such kind of problem and insert right insertion order for records.
I did this because i was not having any primary key or unique or compost key in my table. So to identify which record is first entered, i introduce identity column. I was thinking that it will allocate record number according to insertion order.
If it's possible for you to move data in a new table then this is an approach which is basically recommended by Microsoft:
/*************
Preparing for the example, create tables, insert sample data,...
**************/
-- Your existing table
CREATE TABLE dbo.oldtable
(
colA int,
colB nvarchar(10)
)
-- The new table, same structure + new identity column:
CREATE TABLE dbo.newtable
(
colID int IDENTITY(1,1),
colA int,
colB nvarchar(10)
)
--create unique clustered index on new identity column
create unique clustered index ucx_newtable
on dbo.newtable (colID ASC)
--create other indexes as you need them
create index idx_newtable
on dbo.newtable (colA ASC)
--sample data
insert into dbo.oldtable(colA,colB)
values (16,'this'),(17,'is'),(225,'an'),(300,'example')
/*************
Data Movement
**************/
BEGIN TRANSACTION
BEGIN TRY
--move data to new table including new id column which is generated by
--colA, which gives us the order from old to new in this example
SET IDENTITY_INSERT dbo.newtable ON --So we can insert into the colID identity column
INSERT INTO dbo.newtable(colID, colA,colB)
SELECT ROW_NUMBER() OVER(ORDER BY colA ASC) AS colID --this will generate numbers beginning from 1
,colA, colB
FROM dbo.oldtable
SET IDENTITY_INSERT dbo.newtable OFF
--rename old table / or drop it if you want
EXEC sp_rename #objname = 'dbo.oldtable', #newname = 'dbo.oldtable_xyz'
EXEC sp_rename #objname = 'dbo.newtable', #newname = 'dbo.oldtable'
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
ROLLBACK TRANSACTION
END CATCH

Add identity increment property to existing tables at once

I have multiple tables in database all table has id column which is primary key.
I want a script by which i can add identity property to all tables at once rather than I go and change one by one.
You can't alter the existing columns for identity.
You have 2 options:
Create a new table with identity & drop the existing table
Create a new column with identity & drop the existing column
But take spl care when these columns have any constraints / relations.
For already craeted table Names
Drop table Names
Create table Names
(
ID int,
Name varchar(50)
)
Insert Into Names Values(1,'SQL Server')
Insert Into Names Values(2,'ASP.NET')
Insert Into Names Values(4,'C#')
In this Approach you can retain the existing data values on the newly
created identity column
CREATE TABLE dbo.Tmp_Names
(
Id int NOT NULL IDENTITY (1, 1),
Name varchar(50) NULL
) ON [PRIMARY]
go
SET IDENTITY_INSERT dbo.Tmp_Names ON
go
IF EXISTS(SELECT * FROM dbo.Names)
INSERT INTO dbo.Tmp_Names (Id, Name)
SELECT Id, Name FROM dbo.Names TABLOCKX
go
SET IDENTITY_INSERT dbo.Tmp_Names OFF
go
DROP TABLE dbo.Names
go
Exec sp_rename 'Tmp_Names', 'Names'
In this approach you can’t retain the existing data values on the
newly created identity column;
The identity column will hold the sequence of number
Alter Table Names Add Id_new Int Identity(1,1)
Go
Alter Table Names Drop Column ID
Go
Exec sp_rename 'Names.Id_new', 'ID','Column'
Source 1
What you can do is write a quick query to generate the SQL for you
like so:
USE INFORMATION_SCHEMA;
SELECT
CONCAT("ALTER TABLE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` CONVERT TO CHARACTER SET UTF8;")
AS MySQLCMD FROM TABLES
WHERE TABLE_SCHEMA = "your_schema_goes_here";
Then you can run the output from this to do what you need.
Source 2
EDIT
You could check Altering Multiple Tables at once

How to Alter a table for Identity Specification is identity SQL Server

not working
ALTER TABLE ProductInProduct ALTER COLUMN Id KEY IDENTITY (1, 1);
Check Image
I have a table ProductInProduct is want its id should be Unique..
You cannot "convert" an existing column into an IDENTITY column - you will have to create a new column as INT IDENTITY:
ALTER TABLE ProductInProduct
ADD NewId INT IDENTITY (1, 1);
Update:
OK, so there is a way of converting an existing column to IDENTITY. If you absolutely need this - check out this response by Martin Smith with all the gory details.
You can't alter the existing columns for identity.
You have 2 options,
Create a new table with identity & drop the existing table
Create a new column with identity & drop the existing column
Approach 1. (New table) Here you can retain the existing data values on the newly created identity column.
CREATE TABLE dbo.Tmp_Names
(
Id int NOT NULL
IDENTITY(1, 1),
Name varchar(50) NULL
)
ON [PRIMARY]
go
SET IDENTITY_INSERT dbo.Tmp_Names ON
go
IF EXISTS ( SELECT *
FROM dbo.Names )
INSERT INTO dbo.Tmp_Names ( Id, Name )
SELECT Id,
Name
FROM dbo.Names TABLOCKX
go
SET IDENTITY_INSERT dbo.Tmp_Names OFF
go
DROP TABLE dbo.Names
go
Exec sp_rename 'Tmp_Names', 'Names'
Approach 2 (New column) You can’t retain the existing data values on the newly created identity column, The identity column will hold the sequence of number.
Alter Table Names
Add Id_new Int Identity(1, 1)
Go
Alter Table Names Drop Column ID
Go
Exec sp_rename 'Names.Id_new', 'ID', 'Column'
See the following Microsoft SQL Server Forum post for more details:
http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/04d69ee6-d4f5-4f8f-a115-d89f7bcbc032
You don't set value to default in a table. You should clear the option "Default value or Binding" first.

How to change programmatically non-identity column to identity one?

I have a table with column ID that is identity one. Next I create new non-identity column new_ID and update it with values from ID column + 1. Like this:
new_ID = ID + 1
Next I drop ID column and rename new_ID to name 'ID'.
And how to set Identity on this new column 'ID'?
I would like to do this programmatically!
As far as I know, you have to create a temporary table with the ID field created as IDENTITY, then copy all the data from the original table. Finally, you drop the original table and rename the temporary one. This is an example with a table (named TestTable) that contains only one field, called ID (integer, non IDENTITY):
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_TestTable
(
ID int NOT NULL IDENTITY (1, 1)
) ON [PRIMARY]
GO
SET IDENTITY_INSERT dbo.Tmp_TestTable ON
GO
IF EXISTS(SELECT * FROM dbo.TestTable)
EXEC('INSERT INTO dbo.Tmp_TestTable (ID)
SELECT ID FROM dbo.TestTable WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_TestTable OFF
GO
DROP TABLE dbo.TestTable
GO
EXECUTE sp_rename N'dbo.Tmp_TestTable', N'TestTable', 'OBJECT'
GO
COMMIT
Looks like SQL Mobile supports altering a columns identity but on SQL Server 2005 didn't like the example from BOL.
So your options are to create a new temporary table with the identity column, then turn Identity Insert on:
Create Table Tmp_MyTable ( Id int identity....)
SET IDENTITY_INSERT dbo.Tmp_Category ON
INSERT Into Tmp_MyTable (...)
Select From MyTable ....
Drop Table myTable
EXECUTE sp_rename N'dbo.Tmp_MyTable', N'MyTable', 'OBJECT'
Additionally you can try and add the column as an identity column in the first place and then turn identity insert on. Then drop the original column. But I am not sure if this will work.
Guessing you didn't have much luck with your task....
In table design, you should be able to go into properties and under Identity Specification change (Is Identity) to Yes and assign the column primary key if it formerly had the primary key.
From SqlServerCentral.com
Changing from Non-IDENTITY to IDENTITY and vice versa
An Identity is a property that is set at the time the table is created or a new column is added in alter table statement. You can't alter the column and set it to identity and it is impossible to have two identity columns within the same table.
Depending on the size of the table, is it possible to simply create a new table? copy over the schema of the old one and then use SET IDENTITY_INSERT ON to populate the new identity column with what you want from the old one.