Remove identity or formula with out dropping and recreating table - sql

What I want is to set or remove identity or formula for a column of table in sql , sql generate this code :
CREATE TABLE dbo.Tmp_Table
(
a int NOT NULL IDENTITY (1, 1)
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Table SET (LOCK_ESCALATION = TABLE)
GO
SET IDENTITY_INSERT dbo.Tmp_Table ON
GO
IF EXISTS(SELECT * FROM dbo.[Table])
EXEC('INSERT INTO dbo.Tmp_Table (a)
SELECT a FROM dbo.[Table] WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_Table OFF
GO
DROP TABLE dbo.[Table]
GO
EXECUTE sp_rename N'dbo.Tmp_Table', N'Table', 'OBJECT'
I wrote a script to set or remove identity or formula with out dropping a table and recreating it because I don't have all of the column's information such as primary key or foreign key.
(I want to create this such as set NULL or not NULL that you just write a column name and a column type).
How can i do this? Is it possible to do it?

Short answer is that you can't do it easily. If you want to drop an identity specification, you have to drop and re-create the column (which is less invasive than dropping the table, but still a pain). To keep the data you would need to create a copy of the column without the identity specification and then copy the data across before dropping the original column and renaming the new one.
The problem with that is if you have a foreign key referencing that column then you need to drop that first and re-create it afterwards. Luckily you can get all the information about a column by querying the system catalog views. The ones you'd be interested in are:
sys.columns
sys.foreign_keys
sys.foreign_key_columns
You might also want sys.indexes and within that you'll want to check is_primary_key = 1 to get information on a primary key and to get the PK columns you'll need to look at sys.index_columns. I won't detail how to join them all (they are all linked) as you can find that in the MSDN documentation.
It's a proper pain in the neck to get rid of an identity specification, I feel your pain - I've been there myself.

Related

SQL Server Change Primary Key Data Type

I am working on SQL Server 2012:
I have a table with a primary key column as INT. I need to change this to a GUID.
Do I alter the table and remove int column as primary key?
Add the GUID column and set it as Primary and drop the old INT column?
Thank you.
You can't change primary key column,unless you drop it..Any operations to change its data type will lead to below error..
The object 'XXXX' is dependent on column 'XXXX'.
Only option is to
1.Drop primary key
2.change data type
3.recreate primary key
ALTER TABLE t1
DROP CONSTRAINT PK__t1__3213E83F88CF144D;
GO
alter table t1
alter column id varchar(10) not null
alter table t1 add primary key (id)
From 2012,there is a clause called (DROP_EXISTING = ON) which makes things simple ,by dropping the clustered index at final stage and also keeping old index available for all operations..But in your case,this clause won't work..
So i recommend
1.create new table with desired schema and indexes,with different name
2.insert data from old table to new table
3.finally at the time of switch ,insert data that got accumulated
4.Rename the table to old table name
This way you might have less downtime
You can change the date type of the primary key in three steps
Step 1 :- Drop the constraint associated with the Primary key
ALTER TABLE table_name
DROP CONSTRAINT constraint_name;
Step 2 :- Alter the Primay key column to a valid primary key data type
ALTER TABLE table_name
ALTER COLUMN pk_column_name target_data_type(size) not null;
Step 3 :- Make the altered column primary key again
ALTER TABLE table_name
ADD PRIMARY KEY (pk_column_name);
PS :-
You can get the Constraint name from the error message when you try to alter the
pk_column
If you already have data in the pk_column make sure the source and target data type of the column both can be used for the existing data. else another two steps would be needed to move the existing data to a temporary column and then perform the steps and bring back that data after vetting and dropping that temporary column.
Below is a script I wrote to help us deploy a change to primary key column data type.
This script assumes there aren't any non-primary key constraints (e.g. foreign keys) depending on this column.
It has a few safety checks as this was designed to be deployed to different servers (dev, uat, live) without creating side effects if the table was somehow different on a server.
I hope this helps someone. Please let me know if you find anything wrong before down-voting. I'm more than happy to update the script.
IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS C WITH (NOLOCK) WHERE C.TABLE_CATALOG = '<<DB>>' AND C.TABLE_SCHEMA = 'dbo' AND C.TABLE_NAME = '<<Table>>'
AND C.COLUMN_NAME = '<<COLUMN>>' AND C.DATA_TYPE = 'int') -- <- Additional test to check the current datatype so this won't make unnecessary or wrong updates
BEGIN
DECLARE #pkName VARCHAR(200);
SELECT #pkName = pkRef.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pkRef WITH (NOLOCK)
WHERE pkRef.TABLE_CATALOG = '<<DB>>' AND pkRef.TABLE_SCHEMA = 'dbo' AND TABLE_NAME = '<<Table>>'
IF(#pkName IS NOT NULL)
BEGIN
-- Make sure the primary key name is the one you are going to use in script beyond this point.
IF(#pkName != '<<PRIMARY KEY NAME>>')
BEGIN
RAISERROR ('Unexpected primary key name - The primary key found has a different name than expected. Please update the script.', 16, 1);
RETURN;
END
ALTER TABLE dbo.<<Table>>
DROP CONSTRAINT <<PRIMARY KEY NAME>>; -- Note: this is not a string or a variable (just type the PK name)
SELECT 'Dropped existing primary key';
END
ALTER TABLE dbo.<<Table>> ALTER COLUMN ID BIGINT
SELECT 'Updated column type to big int';
ALTER TABLE dbo.<<Table>>
ADD CONSTRAINT <<PRIMARY KEY NAME>> PRIMARY KEY CLUSTERED (<<COLUMN>>);
SELECT 'Created the primary key';
END
ELSE
BEGIN
SELECT 'No change required.';
END
In case other tables reference your PK with indexed FK's, these are the steps you must follow.
In this example, the main table's called Main, the single referencing table Reference. I'm changing the datatype to NVARCHAR(7). To use it:
Find/replace all these table names with your own;
Modify the data type;
You might also need to separately find/replace the dbo schema;
I'm using syntax which includes constraint names - if you want, also update these to your preferred naming conventions.
ALTER TABLE dbo.Main ADD IdNew NVARCHAR(7);
UPDATE dbo.Main SET IdNew = Id;
-- For all tables with FK's to this Main:
ALTER TABLE dbo.Reference ADD MainIdNew NVARCHAR(7);
UPDATE dbo.Reference SET MainIdNew = MainId;
ALTER TABLE dbo.Reference DROP CONSTRAINT FK_Reference_MainId_Main_Id;
DROP INDEX IX_Reference_MainId ON dbo.Reference;
ALTER TABLE dbo.Reference DROP COLUMN MainId;
-- Until here
ALTER TABLE dbo.Main DROP CONSTRAINT PK_Main;
ALTER TABLE dbo.Main DROP COLUMN Id;
EXEC sp_rename 'dbo.Main.IdNew', 'Id', 'COLUMN';
ALTER TABLE dbo.Main ALTER COLUMN Id NVARCHAR(7) NOT NULL;
ALTER TABLE dbo.Main ADD CONSTRAINT PK_Main PRIMARY KEY (Id);
-- Again for all tables with FK's to this Main:
EXEC sp_rename 'dbo.Reference.MainIdNew', 'MainId', 'COLUMN';
ALTER TABLE dbo.Reference ADD CONSTRAINT FK_Reference_MainId_Main_Id FOREIGN KEY (MainId) REFERENCES dbo.Main(Id);
CREATE INDEX IX_Reference_MainId ON dbo.Reference(MainId);
Right in the table you want to change the PK type >> Modify. Go in the column, change the type and save. If you want to see the code for such a change, before saving, you can right-click >> "Generate Change Script ..".
Using Microsoft SQL Server Management Studio do the following:
Open table Design
Change the primary key column type or any other change which is also possible with this way
Right click on the design area and select Generate Change Script
Accept Validation Warning
Preview changes or save them in file.
Profit :)
This works for any change to the table, just bare in mind that SSMS creates a temporary second table to do the difficult changes like primary column type change.
This works for me in version 18.9 of the app.

How to create a surrogate key column in existing table?

I would like to create a new column called PurchaseOrderID in an existing table using SSMS. It combines LineNumber and PONUMBER to create a surrogate key and then I would enter into table design mode and assign it a PK there.
Creating new column:
ALTER TABLE FactPurchaseOrders
ADD PurchaseOrderID VARCHAR(64);
Populating with values:
UPDATE FactPurchaseOrders
SET PurchaseOrderID = (CONVERT(VARCHAR(64), LineNumber) + CONVERT(VARCHAR(64), PONUMBER))
WHERE 1=1;
Currently with this I am unable to assign this column a PK and I believe because it is nullable.
I have also tried creating it in design mode first and the same problem occurs.
That is most certainly the case. After you have run your update, simply alter the columns you will use in your PK to NOT NULL. Since the columns will have values now it can be set as NOT NULL and then it will allow the assignment of PK. Also make sure there isn't already another PK on the table already. There can be only 1!
Update Records
Alter columns to not null
Create PK on fields

How to remove auto increment from table in sql server 2012

I have created a table in SQL Server 2012 with primary key as auto increment. But how can I remove that auto increment property from the table using a SQL query?
If you need to keep the data in that column then create a new column on the table which is of the same type (but a different name), copy the data from the column you want to get rid of to the new one, drop the old column and rename the new. Complete example:
CREATE TABLE test(col1 INT IDENTITY (1,1) NOT NULL, col2 VARCHAR(10) NULL);
ALTER TABLE test ADD col3 INT NULL;
UPDATE test SET col3 = col1;
ALTER TABLE test DROP COLUMN col1;
EXEC sp_rename 'dbo.test.col3', 'col1', 'COLUMN';
The easiest way would be:
Open SQL Server Management Studio.
Locate Server > DataBase > Table.
Right Click on the Table > Select Design.
In the design window, Highlight the column you want to modify.
In the Column Properties Window browse to Identity Specification > Is Identity And set to No.
Go to the toolbar menu > Table Designer > Select Generate Change Script...
Walla, you got the requested script.
I Like using this method for getting scripts, since it allows me to generate scripts I'm not sure how to compose from scratch and thus learning and improving my skills...
If it's a primary key column, then you have to drop the PK first. If there's any tables referencing it, then you'll have to drop these FKs to be able to drop the PK. After that, add another column of the same type, update it with values from identity column, drop the identity column, rename the new column to whatever the name of identity column was (with sp_rename procedure), recreate the PK, recreate the FKs, check if everything went right.
I'd be very careful doing it on a production database. Ensure that noone can access the data while you're doing this.
I searched a lot to find a simple solution to remove the auto increment because i should do a lot of work if i drop the column and the primary key which was a foreign key on another table where I should remove the data that are using my foreign ... finally I ended up with a very simple solution that made my life easy:
SET IDENTITY_INSERT <table_name> ON ;
SET IDENTITY_INSERT [TABLE] OFF .. this allows to remove the auto increment to off state.., so that we have to enter the value in thatcolumn

How to add identity to the column in SQL Server?

I have a table about 10 million rows. We just imported it from another database with SQL Server Management Studio. It creates table but without identity and primary key on primary key column.
I could add the primary key but couldn't add identity. It's all the time timing out when I'm doing it in designer. Even I set time out settings to 0.
I need to create probably another column set primary key and identity, copy data from old, delete old column and rename new one.
Can anyone show me what will be the best way to do it for such big tables, without additional overheating?
You cannot add IDENTITY to an existing column. It just cannot be done.
You'll need to create a new column of type INT IDENTITY and then drop the old column you don't need anymore (and possibly rename the new column to the old name - if that's needed)
Also: I would not do this in the visual designer - this will try to recreate the table with the new structure, copy over all data (all 10 millions rows), and then drop the old table.
It's much more efficient to use straight T-SQL statements - this will do an "in-place" update, non-destructive (no data is lost), and it doesn't need to copy around 10 millions rows in the process...
ALTER TABLE dbo.YourTable
ADD NewID INT IDENTITY(1,1) NOT NULL
When you add a new column of type INT IDENTITY to your table, then it will be automatically populated with consecutive numbers. You cannot stop this from happening, and you also cannot update the values later on.
Neither of those options is really very useful, in the end - you might end up with different ID values.... to do this right, you'd have to:
create the new table ahead of time, with the proper structure and the IDENTITY already in place
then turn on SET IDENTITY_INSERT (yourtable) ON on that table to allow values to be inserted into the identity column
copy over this data from the original source
turn off identity insert again: SET IDENTITY_INSERT (yourtable) OFF
Only with this approach will you be able to get the same ID's in an IDENTITY column in your new table.
Okay. I was able to add identity to the existing primary column with 10 million records. Took me about 30 mins.
The steps:
Change database to single user mode (to make sure no other connections to databse, can cause lock)
Open table in designer mode
Make change. Do not save
Click Generate Change Script button (usually on the left right above the Object Explorer)
Copy generated script
Close designer window (you can run only one instance at the time)
Open new window
Execute script
Done. Now your column has identity :)
You can add IDENTITY to an existing column. It just can be done.
in SSMS Just go to tools-->options-->Designers-->Table And Database Designers and uncheck option Prevent Saving changes that require table re-creation.
Now add identity in designer mode to the required column and save.
One way to set an identity column is during an insert with the option set identity_insert. For example, to change id in this table to identity:
create table YourTable (id int, value varchar(50))
You could use this script:
-- Create empty table as a copy of the original
select top 0 * into YourTable_New from YourTable
-- Drop the old ID column
alter table YourTable_New drop column id
-- Add a new ID column with identity
alter table YourTable_New add id int identity
-- Copy the old values into the identity column
set identity_insert YourTable_New on
insert YourTable_New (id, value) select id, value from YourTable
set identity_insert YourTable_New off
-- Drop the old table and rename the new one
drop table YourTable
exec sp_RENAME 'YourTable_New' , 'YourTable'

Is there a smart way to append a number to an PK identity column in a Relational database w/o total catastrophe?

It's far from the ideal situation, but I need to fix a database by appending the number "1" to the PK Identiy column which has FK relations to four other tables. I'm basically making a four digit number a five digit number. I need to maintain the relations. I could store the number in a var, do a Set query and append the 1, and do that for each table...
Is there a better way of doing this?
You say you are using an identity data type for your primary key so before you update the numbers you will have to SET IDENTITY_INSERT ON (documentation here) and then turn it off again after the update.
As long as you have cascading updates set for your relations the other tables should be updated automatically.
EDIT: As it's not possible to change an identity value I guess you have to export the data, set the new identity values (+10000) and then import your data again.
Anyone have a better suggestion...
Consider adding another field to the PK instead of extending the length of the PK field. Your new field will have to cascade to the related tables, like a field length increase would, but you get to retain your original PK values.
My suggestion is:
Stop writing to the tables.
Copy the tables to new tables with the new PK.
Rename the old tables to backup names.
Rename the new tables to the original table name.
Count the rows in all the tables and double check your work.
Continue using the tables.
Changing a PK after the fact is not fun.
If the column in question has an identity property on it, it gets complicated. This is more-or-less how I'd do it:
Back up your database.
Put it in single user mode. You don't need anybody mucking around whilst you do the surgery.
Execute the ALTER TABLE statements necessary to
disable the primary key constraint on the table in question
disable all triggers on the table in question
disable all foreign key constraints referencing the table in question.
Clone your table, giving it a new name and a column-for-column identical definitions. Don't bother with any triggers, indices, foreign keys or other constraints. Omit the identity property from the table's definition.
Create a new 'map' table that will map your old id values to the new value:
create table dbo.pk_map
(
old_id int not null primary key clustered ,
new_id int not null unique nonclustered ,
)
Populate the map table:
insert dbo.pk_map
select old_id = old.id ,
new_id = f( old.id ) // f(x) is the desired transform
from dbo.tableInQuestion old
Populate your new table, giving the primary key column the new value:
insert dbo.tableInQuestion_NEW
select id = map.id ,
...
from dbo.tableInQuestion old
join dbo.pk_map map on map.old_id = old.id
Truncate the original table: TRUNCATE dbo.tableInQuestion. This should work—safely—since you've disabled all the triggers and foreign key constraints.
Execute SET IDENTITY_INSERT dbo.tableInQuestion ON.
Reload the original table:
insert dbo.tableInQuestion
select *
from dbo.tableInQuestion_NEW
Execute SET IDENTITY_INSERT dbo.tableInQuestion OFF
Execute drop table dbo.tableInQuestion_NEW. We're all done with it.
Execute DBCC CHECKIDENT( dbo.tableInQuestion , reseed ) to get the identity counter back in sync with the data in the table.
Now, use the map table to propagate the changed primary key column down the line. Depending on your E-R model, this can get complicated as foreign keys referencing the updated column may themselves be part of a composite primary key.
When you're all done, start re-enabling the constraints and triggers you disabled. Make sure you do this using the WITH CHECK option. Fix any problems thus uncovered.
Finally, drop the map table, and clear the single user flag and bring your system(s) back online.
Piece of cake! (or something.)
Consider this approach:
Reset the identity seed to the 10000 + the current seed.
Set identity insert on
Insert into the table from the values in the table and add 10000 to the identity column on the way.
EX:
Set identity insert on
Insert Table(identity, column1, eolumn2)
select identity + 10000, column1, column2
From Table
Where identity < origional max identity value
After the insert you know the identity is exactly 10000 more than the origional.
Update the foreign keys by addding 10000.