MSSQL add IDENTITY by altering all tables columns - sql

I have a database in which all the tables have column named ID. I need to alter all tables in database and add identity to these columns. Is it possible with some query ? Or do I have to do it manually?
Thank you very much.

Unfortunately in SQL Server you cannot add identity property to existing columns. You need to drop an existing one, then create new with this property. You can automate this task by quering system tables and using dynamic sql. But if you already have some data in ID column this will make things more tricky because you need to preserve existing data.
Here is a script for a single table, automating this for all tables in database using dynamic sql will be kinda tricky...
Table Test_table has 2 columns: id and val.
-- Move data to temp storage
SELECT ID,
VAL
INTO #temp_table
FROM dbo.test_table
-- Remove data from original table
DELETE
FROM dbo.test_table
-- Drop and Create ID column
ALTER TABLE dbo.test_table
DROP COLUMN ID
ALTER TABLE dbo.test_table
ADD ID int IDENTITY(1,1)
-- Move data back to original table
SET IDENTITY_INSERT dbo.test_table ON
INSERT INTO dbo.test_table (ID, VAL)
SELECT ID, VAL
FROM #temp_table
DECLARE #MaxID int
SELECT #MaxID = MAX(ID) + 1
FROM dbo.test_table
SET IDENTITY_INSERT dbo.test_table OFF
-- Reseed IDENTITY property
DBCC CHECKIDENT ('dbo.test_table', RESEED, #MaxID)

There is no way to do this for all tables. Here's what I'd do: Use T-SQL to generate a (big) script that performs all the changes, then manually run that script.
You can add the identity property to existing columns without data movement using SWITCH.

Related

How can I prevent a record inserted by an SQL trigger attempting to set the identity column

I'm attempting to create a 'history' table that gets updated every time a row on the source table is updated.
Here's the (SQL Server) code I'm using to create the history table:
DROP TABLE eventGroup_History
SELECT
CAST(NULL AS UNIQUEIDENTIFIER) AS NewId,
CAST(NULL AS varchar(255)) AS DoneBy,
CAST(NULL AS varchar(255)) AS Operation,
CAST(NULL AS datetime) AS DoneAt,
*
INTO
eventGroup_History
FROM
eventGroup
WHERE
1 = 0
GO
ALTER TABLE eventGroup_History
ALTER COLUMN NewId UNIQUEIDENTIFIER NOT NULL
go
ALTER TABLE eventGroup_History
ADD PRIMARY KEY (NewId)
GO
ALTER TABLE eventGroup_History
ADD CONSTRAINT DF_eventGroup_History_NewId DEFAULT NewSequentialId() FOR NewId
GO
The trigger is created like this:
drop trigger eventGroup_LogUpdate
go
create trigger eventGroup_LogUpdate
on dbo.eventGroup
for update
as
declare #Now as DateTime = GetDate()
set nocount on
insert into eventGroup_History
select #Now, SUser_SName(), 'update-deleted', *
from deleted
insert into eventGroup_History
select SUser_SName(), 'update-inserted', #Now, *
from inserted
go
exec sp_settriggerorder #triggername = 'eventGroup_LogUpdate', #order = 'last', #stmttype = 'update'
But when I update a row in SQL Server Management Studio, I get a message:
The data in row 2 was not committed.
Error Source: .Net SqlClient Data Provider.
Error Message: Conversion failed when converting from a character string to uniqueidentifier.
I think that the trigger is attempting to insert the SUserSName() as the first column of the row but that is the PK NewId:
There are no other uniqueidentifier columns in the table.
If I add row from the SQL Management Studio's edit grid, the row gets added without me having to specify the NewId value.
So, why is the SQL Server trigger attempting to populate NewId with first item in the INSERT INTO clause rather than skipping it to let the normal IDENTITY operation provide a value?
(And how do I stop this happening so that the trigger works?)
Because the automatic skipping only applies to IDENTITY columns - a GUID column set with the NewSequentialId() constraint behaves similarly to IDENTITY in many ways but not this one.
You can achieve what you are looking for by specifying the columns for the INSERT explicitly.
If you're going to use a default value on your NewId column, you need to explicitly list the column names in the INSERT statements. By default, SQL Server will insert the columns in the order they're listed in the SELECT, unless you give it enough information to do otherwise. Listing out the columns explicitly is a best practice, one way or the other, in order to avoid just this sort of unanticipated result.
So your statements will end up looking like this:
INSERT INTO eventGroup_History
(
DoneBy,
Operation,
DoneAt,
<All the other columns that are masked by the *>
)
SELECT....

Cloning a table definition to a table variable in SQL Server

Is there a way to clone the table definition from an existing table and recreate as a table variable?
DECLARE #TempTable1 TABLE (ID INT, Description VARCHAR(256))
I need to recreate a set of tables with same number of columns and definitions without repeating the DECLARE TABLE statement.
This process is available on MySQL as below.
CREATE TABLE TempTable1 LIKE TempTableMain;
Is it possible to do this is Microsoft SQL Server?
Please note that the actual scenario contains more that 60 columns in the #TempTable and need to create more than 10 instances from the original table.
I am not talking about data insertion or SELECT ion from another table as below. I need to create the table definition.
DECLARE #TempTable TABLE(ID INT, Description VARCHAR(100))
INSERT INTO #TempTable
VALUES (1, 'Test1'), (1, 'Test1');
SELECT *
INTO #TempTable2
FROM #TempTable1
SELECT * FROM #TempTable2
Create a user defined type with the columns of your table, lets say like that:
CREATE TYPE MyTableType AS TABLE (ID INT, Description VARCHAR(256));
And then declare your table variables using this type:
DECLARE #Table1 MyTableType;
DECLARE #Table2 MyTableType;
DECLARE #Table3 MyTableType;
SQL Server management studio gives you the option to create a sql script to create an already existing table.
Right click your table -> script table as -> CREATE To -> New Query Editor window
This way you dont have to write out the whole query every single time.
You could even create a stored procedure which takes as argument the name of your to be created table and run this from a while loop.
You can perform the following command:
SELECT * INTO #MyTable_tmp FROM MyTable
Then modify your MyTable, and copy your data back in. Other approaches I've seen is to create a new table calling it Mytable_Tmp (Not a temp table), which will be your new table.
Then copy your data doing any migrations you need. Then you will drop the original table and do a rename on Mytable.
When you run SELECT * INTO #MyTable FROM MyTable, SQL Server creates a new temporary table called #MyTable that matches each column and data type from your select clause. In this case we are selecting * so it will match MyTable. This only creates the columns it doesn't copy defaults, constraints indexes or anything else.
If you are using table variables, it means that you don't want to use them in long period of time, as they will be "forgotten" after every script completion.
So, easiest in my opinion is to use such construct:
IF OBJECT_ID('tempdb.dbo.#tmpTable', 'U') IS NOT NULL
DROP TABLE #tmpTable;
SELECT * INTO #tmpTable FROM MyPrimaryTable
It creates temporary table exactly like yours, if you want empty table, you can just use:
SELECT * INTO #tmpTable FROM MyPrimaryTable WHERE 1 = 0
Then, temporary table will have exact same schema as your primary table.
You can apply as many times as you need (create as many temporary tables as you need).
You could use regular tables instead of temporary tables as well.
If you want to re-create table after dropping the existing table then you can use the below query.
/*
Create brands table
*/
-- Old block of code
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[TOY].[BRANDS]') AND type in (N'U'))
DROP TABLE [TOY].[BRANDS]
GO
-- New block of code
DROP TABLE IF EXISTS [TOY].[BRANDS]
GO
-- Add new table
CREATE TABLE TOY.BRANDS
(
ID INT NOT NULL,
NAME VARCHAR(20) NULL
)
GO
-- Load the table with data
INSERT INTO TOY.BRANDS (ID, NAME) VALUES
(1, 'Ford'),
(2, 'Chevy'),
(3, 'Dodge'),
(4, 'Plymouth'),
(5, 'Oldsmobile'),
(6, 'Lincoln'),
(7, 'Mercury');
GO

SQL attempting to start an identity at a dynamic variable

In a nutshell, I have a temp table which stores a range of data. The number of rows could be dynamic depending on when this query is run. I'm then trying to alter the table and add an identity which I want to start at a defined value that I have chosen.
Whatever I seem to have tried, when viewing the data the identity column always starts at 1…and increments and not the value I specified.
--At this point of the code the data is already in the table!
Set existingNumber =
(
--Get a number from a table
)
Set existingNumber = existingNumber + 1
Alter table #myTable
Add testID bigINT Identity
DBCC CHECKIDENT (#myTable, RESEED, #existingNumber)
Is there a way that I can simply restart the Identity column for pre existing values?
I have tried looking at creating the identity with the table but this causes another problem due to how our company framework is unfortunately.
EDIT:
Using SQL Management Studio
Your #existingNumber variable is not being set correctly.
The below example works fine..
declare #existingNumber int = 1000
create table #test (col1 varchar(20))
alter table #test add testId bigint Identity
dbcc checkident (#test, reseed, #existingNumber)
insert into #test values ('test record')
select * from #test
drop table #test

SQL server convert int field to bit

I have a big database and I should to normalize it. One of the table contains field with type "integer" but it contains only 1 and 0 values. So it is good reason to convert this field to bit type. But when I try to save changes in SQL Server Management Studio it tells me that I can't do it. Also I have many field with values like nvarchar that should be converted to int or float that should be converted to int too.
Moreover I should create migration scripts for all changes so I can update real database without loosing data. Maybe somebody knows useful utility for this?
EDIT: It tells me that I can't update unable without drop it. And I want to update table without losing any data.
SQL version 2014
---Create one Temp. Column
Alter Table [dbo].[Demo2]
Add tempId int
GO
--Copy Data in temp. Coulmn
Update [dbo].[Demo2] set tempId=Id
--Drop column which you want to modify
Alter Table [dbo].[Demo2]
Drop Column Id
Go
--Create again that column with bit type
Alter Table [dbo].[Demo2]
Add Id bit
GO
--copy date back
Update [dbo].[Demo2] set Id=tempId
--drop temp column
Alter Table [dbo].[Demo2]
Drop Column tempId
Go
Here's how to add a new column to a table, set that column to the old column and then remove the old column
CREATE TABLE #test
(inttest int
)
Insert [#test]
( [inttest] )
Values ( 0
)
Insert [#test]
( [inttest] )
Values ( 1
)
Alter Table [#test] Add bittest bit
Update [#test] Set bittest=inttest
Alter Table [#test] Drop Column [inttest]
SELECT * FROM [#test] [T]
To generate migration script you don't need a special utility, SSMS does it pretty well.
Right-click the table in SSMS object explorer. Choose Design item in the context menu. Change the type of the column. In the main menu Table Designer choose item Generate Change Script. Save the generated script to a file, review it and make sure you understand each line in it before you run it on a production system. Adjust the script if needed.
On the other hand, to change the column type from int to bit you can use the ALTER TABLE statement:
ALTER TABLE dbo.TableName
ALTER COLUMN ColumnName bit NOT NULL
Before running this you should check that actual int values are indeed only 0 and 1.
After reading of all comments and posts I found solution in building procedure which will convert passed table and column in required. So I wrote this function
IF EXISTS (select * from dbo.sysobjects where id = object_id(N'IntToBit') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
DROP PROCEDURE IntToBit
GO
IF OBJECT_ID('convertion_table', 'U') IS NOT NULL
DROP TABLE dbo.convertion_table;
go
CREATE TABLE dbo.convertion_table
(
bitTypeColumn bit NOT NULL DEFAULT 0,
intTypeColumnt integer ,
)
go
CREATE procedure IntToBit
#table nvarchar(150),
#column nvarchar(150)
AS
begin
DECLARE #sql nvarchar(4000)
SELECT #sql ='
--copy data to temp table
INSERT INTO convertion_table (bitTypeColumn)
SELECT '+#column +'
FROM ' +#table+'
--Drop column which you want to modify
Alter Table ' +#table+'
Drop Column '+#column +'
--Create again that column with bit type
Alter Table ' +#table+'
Add '+#column +' bit NOT NULL DEFAULT(0)
--copy date back
INSERT INTO '+#table+'('+#column+')
SELECT bitTypeColumn
FROM convertion_table
--cleare temp table
--DELETE bitTypeColumn FROM convertion_table
'
exec sp_executesql #sql
end
GO
and then call it passing field and table name :
exec dbo.IntToBit #table = 'tbl_SystemUsers', #column='intUseLogin';
Special thanks to Chris K and Hitesh Thakor
Simply Use TSql script to modify the table rather than using the designer
ALTER TABLE YourTableNameHere
ALTER COLUMN YourColumnNameHere INT
If you are using sql Server then you might wanna generate script for the table before altering the table so that you dont loose any data ..and you can simply retrieve everything using the script

Change Increment value for Identity - SQL Server 2005

I would like to change increment value of IDENTITY column in database and I have below restrictions:
Can't drop the column.
Having around 20k rows.
Dropping table and recreate table with changed increment value would be the solution. I don't know the syntax.
Can you please suggest the syntax or other best possible solution?
Thanks in Advance!
If i understand you correctly base on your response to my comment, you backed up the data of the orig table in temp table, then you deleted the orig table and you want to recreate an orig table.
If that is the case , you need the IDENTITY_INSERT to set ON and OFF, because the identity of the table is unique.
The syntax is:
SET IDENTITY_INSERT [TableName] ON -- set to on
-- Put your insert statement here
-- insert the data from backed up temp table to your new table
SET IDENTITY_INSERT [TableName] OFF -- set to off
If you can accept recreating table, there is no magic about the recreating table syntax.
CREATE TABLE temp_Table
(
-- Identity column with new settings
-- other columns
);
INSERT INTO temp_Table
SELECT -- Columns except identity column
FROM old_table;
DROP TABLE old_Table;
EXEC sp_rename 'temp_Table', 'old_Table';
However, you have to handle foreign key by yourself.
Altering identity column after table creation is not possible.
Instead, reset SEED value using the below command.
DBCC CHECKIDENT('tablename', RESEED, 15)