This answer is very similar to This Answer, with little differences.
For example you have 3 tables like this, with two foreign key
DDL:
CREATE TABLE [Table_1]
(
[id] [int] NOT NULL PRIMARY KEY,
[Name] [varchar](10) NULL
)
GO
CREATE UNIQUE NONCLUSTERED INDEX Table_1_Index
ON [Table_1] ([Name]);
CREATE TABLE [Table_2]
(
[id] [int] NOT NULL
FOREIGN KEY REFERENCES [Table_1]([id]) ON UPDATE CASCADE,
[car] [varchar](10) NULL
)
GO
CREATE TABLE [Table_3]
(
[id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] [varchar](10) NULL
FOREIGN KEY REFERENCES [Table_1]([Name])
)
GO
INSERT INTO [Table_1]
VALUES (10000, 'John'), (10001, 'Mike')
INSERT INTO [Table_2]
VALUES (10000, 'Benz'), (10000, 'Volvo'), (10001, 'BMW')
INSERT INTO [Table_3]
VALUES ('John')
GO
If you want add identity to id
column in Table_1
with dbo
schema, and want to start from 10000 with 1 increment, run this query:
DECLARE @Schema SysName = 'dbo'
DECLARE @TableName SysName = 'Table_1'
DECLARE @ColumnName SysName = 'id'
DECLARE @IdentityType VARCHAR(20) = 'IDENTITY(10000,1)'
DECLARE @Table_Name SYSNAME = QUOTENAME(@Schema) + '.' + QUOTENAME(@TableName)
DECLARE @SQLCreateTable NVARCHAR(MAX)
DECLARE @SQLFK NVARCHAR(MAX)
DECLARE @SQL NVARCHAR(MAX)
--get foreign keys
;WITH fk_columns AS
(
SELECT
constraint_object_id,
OBJECT_NAME(constraint_object_id) KeyName,
OBJECT_NAME(fkc.parent_object_id) FKTable,
OBJECT_NAME(fkc.referenced_object_id) PKTable,
COL_NAME(fkc.parent_object_id, parent_column_id) FKColumn,
COL_NAME(fkc.referenced_object_id, referenced_column_id) PKColumn,
delete_referential_action,
update_referential_action,
is_not_trusted
FROM
sys.foreign_key_columns fkc
JOIN
sys.foreign_keys fk ON fk.object_id = fkc.constraint_object_id
WHERE
fkc.referenced_object_id = OBJECT_ID(@Table_Name)
)
SELECT
@SQLFK = ISNULL((SELECT (
SELECT CHAR(13) +
'ALTER TABLE ' + fk.FKTable + ' WITH'
+ CASE WHEN fk.is_not_trusted = 1
THEN ' NOCHECK'
ELSE ' CHECK'
END +
' ADD CONSTRAINT [' + fk.KeyName + '] FOREIGN KEY('
+ STUFF((
SELECT
', [' + k.FKColumn + ']'
FROM
fk_columns k
WHERE
k.constraint_object_id = fk.constraint_object_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')' +
' REFERENCES '+@Table_Name+' ('
+ STUFF((
SELECT
', [' + k.PKColumn + ']'
FROM
fk_columns k
WHERE
k.constraint_object_id = fk.constraint_object_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')'
+ CASE
WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE'
WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL'
WHEN fk.delete_referential_action = 3 THEN ' ON DELETE SET DEFAULT'
ELSE ''
END
+ CASE
WHEN fk.update_referential_action = 1 THEN ' ON UPDATE CASCADE'
WHEN fk.update_referential_action = 2 THEN ' ON UPDATE SET NULL'
WHEN fk.update_referential_action = 3 THEN ' ON UPDATE SET DEFAULT'
ELSE ''
END
+ CHAR(13) + 'ALTER TABLE ' + fk.FKTable + ' CHECK CONSTRAINT [' + fk.KeyName + ']' + CHAR(13)
FROM fk_columns fk WITH (NOWAIT)
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
--drop foreign keys
;WITH fk_columns AS
(
SELECT
OBJECT_NAME(constraint_object_id) KeyName,
OBJECT_NAME(fkc.parent_object_id) FKTable
FROM
sys.foreign_key_columns fkc
JOIN
sys.foreign_keys fk ON fk.object_id = fkc.constraint_object_id
WHERE
fkc.referenced_object_id = OBJECT_ID(@Table_Name)
)
SELECT @SQL = ISNULL((SELECT (
SELECT
CHAR(13) + 'ALTER TABLE ' + fk.FKTable +
' DROP CONSTRAINT [' + fk.KeyName + ']' + CHAR(13)
FROM
fk_columns fk WITH (NOWAIT)
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
EXECUTE sp_executesql @SQL
--find not exist table name
DECLARE @i INT = 1
WHILE OBJECT_ID(QUOTENAME(@Schema) + '.' +QUOTENAME(@TableName) + '_Temp' + CAST(@i AS varchar), 'U') IS NOT NULL
SET @i += 1
DECLARE @TempName SysName = @TableName + '_Temp' + CAST(@i AS VARCHAR)
DECLARE @Temp_Name SysName = QUOTENAME(@Schema) + '.' +QUOTENAME(@TableName + '_Temp' + CAST(@i AS VARCHAR))
--create temp table like table code
DECLARE @object_id INT = OBJECT_ID(@Table_Name)
;WITH index_column AS
(
SELECT
ic.[object_id],
ic.index_id,
ic.is_descending_key,
ic.is_included_column,
c.name
FROM
sys.index_columns ic WITH (NOWAIT)
JOIN
sys.columns c WITH (NOWAIT) ON ic.[object_id] = c.[object_id] AND ic.column_id = c.column_id
WHERE
ic.[object_id] = @object_id
),
fk_columns AS
(
SELECT
k.constraint_object_id,
cname = c.name,
rcname = rc.name
FROM
sys.foreign_key_columns k WITH (NOWAIT)
JOIN
sys.columns rc WITH (NOWAIT) ON rc.[object_id] = k.referenced_object_id AND rc.column_id = k.referenced_column_id
JOIN
sys.columns c WITH (NOWAIT) ON c.[object_id] = k.parent_object_id AND c.column_id = k.parent_column_id
WHERE
k.parent_object_id = @object_id
)
SELECT @SQLCreateTable = 'CREATE TABLE ' + @Temp_Name + CHAR(13) + '(' + CHAR(13) + STUFF((
SELECT
CHAR(9) + ', [' + c.name + '] ' +
CASE WHEN c.is_computed = 1
THEN 'AS ' + cc.[definition]
ELSE UPPER(tp.name) +
CASE WHEN tp.name IN ('varchar', 'char', 'varbinary', 'binary', 'text')
THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(5)) END + ')'
WHEN tp.name IN ('nvarchar', 'nchar', 'ntext')
THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length / 2 AS VARCHAR(5)) END + ')'
WHEN tp.name IN ('datetime2', 'time2', 'datetimeoffset')
THEN '(' + CAST(c.scale AS VARCHAR(5)) + ')'
WHEN tp.name IN ('decimal', 'numeric')
THEN '(' + CAST(c.[precision] AS VARCHAR(5)) + ',' + CAST(c.scale AS VARCHAR(5)) + ')'
ELSE ''
END +
CASE WHEN c.collation_name IS NOT NULL THEN ' COLLATE ' + c.collation_name ELSE '' END +
CASE WHEN c.name = @ColumnName THEN ' ' +@IdentityType ELSE '' END +
CASE WHEN c.is_nullable = 1 and c.name <> @ColumnName THEN ' NULL' ELSE ' NOT NULL' END +
CASE WHEN dc.[definition] IS NOT NULL and c.name <> @ColumnName THEN ' DEFAULT' + dc.[definition] ELSE '' END
END + CHAR(13)
FROM
sys.columns c WITH (NOWAIT)
JOIN
sys.types tp WITH (NOWAIT) ON c.user_type_id = tp.user_type_id
LEFT JOIN
sys.computed_columns cc WITH (NOWAIT) ON c.[object_id] = cc.[object_id] AND c.column_id = cc.column_id
LEFT JOIN
sys.default_constraints dc WITH (NOWAIT) ON c.default_object_id != 0 AND c.[object_id] = dc.parent_object_id AND c.column_id = dc.parent_column_id
LEFT JOIN
sys.identity_columns ic WITH (NOWAIT) ON c.is_identity = 1 AND c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
WHERE
c.[object_id] = @object_id
ORDER BY
c.column_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, CHAR(9) + ' ')
+ ISNULL((SELECT CHAR(9) + ', CONSTRAINT [' + k.name + '] PRIMARY KEY (' +
(SELECT STUFF((
SELECT ', [' + c.name + '] ' + CASE WHEN ic.is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END
FROM
sys.index_columns ic WITH (NOWAIT)
JOIN
sys.columns c WITH (NOWAIT) ON c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
WHERE
ic.is_included_column = 0
AND ic.[object_id] = k.parent_object_id
AND ic.index_id = k.unique_index_id
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ''))
+ ')' + CHAR(13)
FROM
sys.key_constraints k WITH (NOWAIT)
WHERE
k.parent_object_id = @object_id
AND k.[type] = 'PK'), '') + ')' + CHAR(13)
+ ISNULL((SELECT (
SELECT CHAR(13) +
'ALTER TABLE ' + @Temp_Name + ' WITH'
+ CASE WHEN fk.is_not_trusted = 1
THEN ' NOCHECK'
ELSE ' CHECK'
END +
' ADD CONSTRAINT [' + fk.name + '] FOREIGN KEY('
+ STUFF((
SELECT
', [' + k.cname + ']'
FROM
fk_columns k
WHERE
k.constraint_object_id = fk.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')' +
' REFERENCES [' + SCHEMA_NAME(ro.[schema_id]) + '].[' + ro.name + '] ('
+ STUFF((
SELECT
', [' + k.rcname + ']'
FROM
fk_columns k
WHERE
k.constraint_object_id = fk.[object_id]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
+ ')'
+ CASE
WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE'
WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL'
WHEN fk.delete_referential_action = 3 THEN ' ON DELETE SET DEFAULT'
ELSE ''
END
+ CASE
WHEN fk.update_referential_action = 1 THEN ' ON UPDATE CASCADE'
WHEN fk.update_referential_action = 2 THEN ' ON UPDATE SET NULL'
WHEN fk.update_referential_action = 3 THEN ' ON UPDATE SET DEFAULT'
ELSE ''
END
+ CHAR(13) + 'ALTER TABLE ' + @Temp_Name + ' CHECK CONSTRAINT [' + fk.name + ']' + CHAR(13)
FROM sys.foreign_keys fk WITH (NOWAIT)
JOIN sys.objects ro WITH (NOWAIT) ON ro.[object_id] = fk.referenced_object_id
WHERE fk.parent_object_id = @object_id
FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
+ ISNULL(((SELECT
CHAR(13) + 'CREATE' + CASE WHEN i.is_unique = 1 THEN ' UNIQUE' ELSE '' END
+ CASE i.type WHEN 1 THEN ' CLUSTERED' ELSE ' NONCLUSTERED' END
+ ' INDEX [' + i.name + '] ON ' + @Temp_Name + ' (' +
STUFF((
SELECT ', [' + c.name + ']' + CASE WHEN c.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END
FROM
index_column c
WHERE
c.is_included_column = 0
AND c.index_id = i.index_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')'
+ ISNULL(CHAR(13) + 'INCLUDE (' +
STUFF((
SELECT
', [' + c.name + ']'
FROM
index_column c
WHERE
c.is_included_column = 1
AND c.index_id = i.index_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')', '') + CHAR(13)
FROM
sys.indexes i WITH (NOWAIT)
WHERE
i.[object_id] = @object_id
AND i.is_primary_key = 0
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
), '')
--rename primary key constaint on column from table
DECLARE @PrimaryName SYSNAME
SELECT @PrimaryName=i.name
FROM
sys.index_columns ic WITH (NOWAIT)
JOIN
sys.indexes i WITH (NOWAIT) ON i.object_id = ic.object_id and i.index_id = ic.index_id
WHERE
i.object_id = OBJECT_ID(@Table_Name) and Col_Name(ic.object_id, column_id) = @ColumnName and is_primary_key = 1
SET @SQL = N'EXEC sp_rename ' + @PrimaryName + ', ' + 'ThisMustNotBeExist'+ @PrimaryName + ', N''OBJECT'''
EXECUTE sp_executesql @SQL
--rename index on column from table
DECLARE @IndexName SYSNAME
SELECT
@IndexName = i.name
FROM
sys.index_columns ic WITH (NOWAIT)
JOIN
sys.indexes i WITH (NOWAIT) ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE
i.object_id = OBJECT_ID(@Table_Name)
AND Col_Name(ic.object_id, column_id) = @ColumnName
AND is_primary_key = 0
SET @SQL = N'EXEC sp_rename ' + @Table_Name + '.' + @IndexName + ', ' + 'ThisMustNotBeExist'+ @IndexName + ', N''INDEX'''
EXECUTE sp_executesql @SQL
--run create temp table like table code
EXECUTE sp_executesql @SQLCreateTable
--Move table data to temp data
SET @SQL = N'ALTER TABLE '+ @Table_Name + ' SWITCH TO ' + @Temp_Name
EXECUTE sp_executesql @SQL
--check clean up
SET @SQL = N'IF EXISTS (SELECT * FROM '+ @Table_Name + ') THROW 50000, ''Table is not clear'', 1'
EXECUTE sp_executesql @SQL
--drop table
SET @SQL = N'DROP TABLE '+ @Table_Name
EXECUTE sp_executesql @SQL
--rename temp table to table
EXEC sys.sp_rename @Temp_Name, @TableName, 'OBJECT';
--create foreign keys
EXECUTE sp_executesql @SQLFK
DBCC CHECKIDENT(@TableName, RESEED)
Note
- This code only copy keys and indexes, if you have other things on that table, you loose them after running this code
If you want copy triggers or extended property of the table too, check this answer and add @SQL2
and @SQL3
to @SQLCreateTable
before executing it