Create table (structure) from existing table - sql-server

How to create new table which structure should be same as another table
I tried
CREATE TABLE dom AS SELECT * FROM dom1 WHERE 1=2
but its not working error occurred

Try:
Select * Into <DestinationTableName> From <SourceTableName> Where 1 = 2
Note that this will not copy indexes, keys, etc.
If you want to copy the entire structure, you need to generate a Create Script of the table. You can use that script to create a new table with the same structure. You can then also dump the data into the new table if you need to.
If you are using Enterprise Manager, just right-click the table and select copy to generate a Create Script.

This is what I use to clone a table structure (columns only)...
SELECT TOP 0 *
INTO NewTable
FROM TableStructureIWishToClone

Copy structure only (copy all the columns)
Select Top 0 * into NewTable from OldTable
Copy structure only (copy some columns)
Select Top 0 Col1,Col2,Col3,Col4,Col5 into NewTable from OldTable
Copy structure with data
Select * into NewTable from OldTable
If you already have a table with same structure and you just want to copy data then use this
Insert into NewTable Select * from OldTable

FOR MYSQL:
You can use:
CREATE TABLE foo LIKE bar;
Documentation here.

Create table abc select * from def limit 0;
This will definite work

Its probably also worth mentioning that you can do the following:
Right click the table you want to duplicate > Script Table As > Create To > New Query Editor Window
Then, where is says the name of the table you just right clicked in the script that has been generated, change the name to what ever you want your new table to be called and click Execute

I use the following stored proc for copying a table's schema, including PK, indexes, partition status. It's not very swift, but seems to do the job. I I welcome any ideas how to speed it up:
/*
Clones a table's schema from an existing table (without data)
if target table exists, it will be dropped first.
The following schema elements are cloned:
* Structure
* Primary key
* Indexes
* Constraints
DOES NOT copy:
* Triggers
* File groups
ASSUMPTION: constraints are uniquely named with the table name, so that we dont end up with duplicate constraint names
*/
CREATE PROCEDURE [dbo].[spCloneTableStructure]
#SourceTable nvarchar(255),
#DestinationTable nvarchar(255),
#PartionField nvarchar(255),
#SourceSchema nvarchar(255) = 'dbo',
#DestinationSchema nvarchar(255) = 'dbo',
#RecreateIfExists bit = 1
AS
BEGIN
DECLARE #msg nvarchar(200), #PartionScript nvarchar(255), #sql NVARCHAR(MAX)
IF EXISTS(Select s.name As SchemaName, t.name As TableName
From sys.tables t
Inner Join sys.schemas s On t.schema_id = s.schema_id
Inner Join sys.partitions p on p.object_id = t.object_id
Where p.index_id In (0, 1) and t.name = #SourceTable
Group By s.name, t.name
Having Count(*) > 1)
SET #PartionScript = ' ON [PS_PartitionByCompanyId]([' + #PartionField + '])'
else
SET #PartionScript = ''
SET NOCOUNT ON;
BEGIN TRY
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 1, Drop table if exists. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
--drop the table
if EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #DestinationTable)
BEGIN
if #RecreateIfExists = 1
BEGIN
exec('DROP TABLE [' + #DestinationSchema + '].[' + #DestinationTable + ']')
END
ELSE
RETURN
END
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 2, Create table. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
--create the table
exec('SELECT TOP (0) * INTO [' + #DestinationTable + '] FROM [' + #SourceTable + ']')
--create primary key
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 3, Create primary key. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255),#count INT
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = #SourceSchema AND TABLE_NAME = #SourceTable AND CONSTRAINT_TYPE = 'PRIMARY KEY'
IF NOT #PKSchema IS NULL AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''
SELECT #PKColumns = #PKColumns + '[' + COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
where TABLE_NAME = #SourceTable and TABLE_SCHEMA = #SourceSchema AND CONSTRAINT_SCHEMA = #PKSchema AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED (' + #PKColumns + ')' + #PartionScript);
END
--create other indexes
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 4, Create Indexes. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max), #type int
set #count=0
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition, type FROM sys.indexes WHERE is_primary_key = 0 and object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition, #type
WHILE ##FETCH_STATUS = 0
BEGIN
set #count =#count +1
DECLARE #Unique nvarchar(255)
SET #Unique = CASE WHEN #IsUnique = 1 THEN ' UNIQUE ' ELSE '' END
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #KeyColumns = ''
SET #IncludedColumns = ''
select #KeyColumns = #KeyColumns + '[' + c.name + '] ' + CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END + ',' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal > 0
order by index_column_id
select #IncludedColumns = #IncludedColumns + '[' + c.name + '],' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal = 0
order by index_column_id
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = ' INCLUDE (' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + ')'
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = ''
ELSE
SET #FilterDefinition = 'WHERE ' + #FilterDefinition + ' '
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 4.' + CONVERT(NVARCHAR(5),#count) + ', Create Index ' + #IndexName + '. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
if #type = 2
SET #sql = 'CREATE ' + #Unique + ' NONCLUSTERED INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition + #PartionScript
ELSE
BEGIN
SET #sql = 'CREATE ' + #Unique + ' CLUSTERED INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition + #PartionScript
END
EXEC (#sql)
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition, #type
END
CLOSE indexcursor
DEALLOCATE indexcursor
--create constraints
SET #msg =' CloneTable ' + #DestinationTable + ' - Step 5, Create constraints. Timestamp: ' + CONVERT(NVARCHAR(50),GETDATE(),108)
RAISERROR( #msg,0,1) WITH NOWAIT
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max), #ColumnName NVARCHAR(255)
DECLARE const_cursor CURSOR FOR
SELECT
REPLACE(dc.name, #SourceTable, #DestinationTable),[definition], c.name
FROM sys.default_constraints dc
INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id
WHERE OBJECT_NAME(parent_object_id) =#SourceTable
OPEN const_cursor
FETCH NEXT FROM const_cursor INTO #ConstraintName, #CheckClause, #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
exec('ALTER TABLE [' + #DestinationTable + '] ADD CONSTRAINT [' + #ConstraintName + '] DEFAULT ' + #CheckClause + ' FOR ' + #ColumnName)
FETCH NEXT FROM const_cursor INTO #ConstraintName, #CheckClause, #ColumnName
END;
CLOSE const_cursor
DEALLOCATE const_cursor
END TRY
BEGIN CATCH
IF (SELECT CURSOR_STATUS('global','indexcursor')) >= -1
BEGIN
DEALLOCATE indexcursor
END
IF (SELECT CURSOR_STATUS('global','const_cursor')) >= -1
BEGIN
DEALLOCATE const_cursor
END
PRINT 'Error Message: ' + ERROR_MESSAGE();
END CATCH
END
GO

try this.. the below one copy the entire structure of the existing table but not the data.
create table AT_QUOTE_CART as select * from QUOTE_CART where 0=1 ;
if you want to copy the data then use the below one:
create table AT_QUOTE_CART as select * from QUOTE_CART ;

I don't know why you want to do that, but try:
SELECT *
INTO NewTable
FROM OldTable
WHERE 1 = 2
It should work.

If you Want to copy Same DataBase
Select * INTO NewTableName from OldTableName
If Another DataBase
Select * INTO NewTableName from DatabaseName.OldTableName

SELECT *
INTO NewTable
FROM OldTable
WHERE 1 = 2

Copy the table structure:-
select * into newtable from oldtable where 1=2;
Copy the table structure along with table data:-
select * into newtable from oldtable where 1=1;

SELECT * INTO newtable
from Oldtable

According to How to Clone Tables in SQL, it is:
CREATE TABLE copyTable LIKE originalTable;
That works for just the sructure. For the structure and the data use this:
CREATE TABLE new_table LIKE original_table;
INSERT INTO new_table SELECT * FROM original_table;

Found here what I was looking for. Helped me recall what I used 3-4 years back.
I wanted to reuse the same syntax to be able to create table with data resulting from the join of a table.
Came up with below query after a few attempts.
SELECT a.*
INTO DetailsArchive
FROM (SELECT d.*
FROM details AS d
INNER JOIN
port AS p
ON p.importid = d.importid
WHERE p.status = 2) AS a;

If you want to create a table with the only structure to be copied from the original table then you can use the following command to do that.
create table <tablename> as select * from <sourcetablename> where 1>2;
By this false condition you can leave the records and copy the structure.

I needed to copy a table from one database another database. For anyone using a GUI like Sequel Ace you can right click table and click 'copy create table syntax' and run that query (you can edit the query, e.g. change table name, remove foreign keys, add/remove columns if desired)

Related

Testing Datawarehouse to see what see what issues might have occurred after nightly jobs have run

I want to be able test all tables in the Data warehouse to see what has changed after nightly jobs have run. I am using the query below to see what tables have no rows however i'd like to expand the testing to see other things such as what fields have null values after the job has run. does anyone do similar testing and have a script that they use for this or any other things I should test for?
select
t.name table_name,
s.name schema_name,
sum(p.rows) total_rows
from
sys.tables t
join sys.schemas s on (t.schema_id = s.schema_id)
join sys.partitions p on (t.object_id = p.object_id)
where p.index_id in (0,1)
group by t.name,s.name
having sum(p.rows) = 0;
i've written the following stored proc that checks all tables in my DWH to see what columns are null. similarly the same can be done for checking what numeric columns are zero.
alter PROCEDURE EMPTYSEARCH
#WHICHTABLE VARCHAR(50)
AS
SET NOCOUNT ON
DECLARE #SQL nVARCHAR(max),
#TABLENAME VARCHAR(max) ,
#COLUMNNAME VARCHAR(max)
CREATE TABLE #RESULTS(TBLNAME VARCHAR(60),COLNAME VARCHAR(60),SQL VARCHAR(600))
SELECT
SYSOBJECTS.NAME AS TBLNAME,
SYSCOLUMNS.NAME AS COLNAME,
TYPE_NAME(SYSCOLUMNS.XTYPE) AS DATATYPE
INTO #FKFINDER
FROM SYSOBJECTS
INNER JOIN SYSCOLUMNS ON SYSOBJECTS.ID=SYSCOLUMNS.ID
WHERE SYSOBJECTS.XTYPE='U'
AND SYSOBJECTS.NAME = #WHICHTABLE
AND TYPE_NAME(SYSCOLUMNS.XTYPE) IN ('VARCHAR','NVARCHAR','CHAR','NCHAR')
ORDER BY TBLNAME,COLNAME
DECLARE C1 CURSOR FOR
SELECT TBLNAME,COLNAME FROM #FKFINDER ORDER BY TBLNAME,COLNAME
OPEN C1
FETCH NEXT FROM C1 INTO #TABLENAME,#COLUMNNAME
WHILE ##FETCH_STATUS <> -1
BEGIN
SET #SQL = '
IF EXISTS(SELECT * FROM [' + #TABLENAME + '] WHERE (select count(*) from [' + #TABLENAME + '] where [' + #COLUMNNAME + '] is null) = (select count(*) from [' + #TABLENAME + '] ))
INSERT INTO #RESULTS(TBLNAME,COLNAME,SQL) VALUES(''' + #TABLENAME + ''',''' + #COLUMNNAME + ''',''
SELECT * FROM [' + #TABLENAME + '] WHERE (select count(*) from [' + #TABLENAME + '] where [' + #COLUMNNAME + '] is null) = (select count(*) from [' + #TABLENAME + '] '') ;'
PRINT #SQL
EXEC (#SQL)
FETCH NEXT FROM C1 INTO #TABLENAME,#COLUMNNAME
END
CLOSE C1
DEALLOCATE C1
SELECT * FROM #RESULTS

delete all lines from all tables of a database

Somebody must have already written a script to delete all lines from all tables of a database.
Using DELETE command is not an option since it can takes ages on large tables.
Of course there are many examples on stackoverflow and elsewhere, but they don't work with tables using foreign keys.
Basically, the script should do this :
Store all foreign keys definition in a temporary table
delete all foreign keys
truncate all tables
restore foreign keys
I think i have it :
IF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL
DROP TABLE #ForeignKeys;
WITH ForeignKeys AS (
SELECT
QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS ParentTable
, QUOTENAME(SCHEMA_NAME(rt.schema_id)) + '.' + QUOTENAME(rt.name) AS ReferenceTable
, QUOTENAME(f.name) AS ConstraintName
, STUFF(Parent.Cols, 1, 1, '') AS ParentColumns
, STUFF(Reference.Cols, 1, 1, '') AS ReferenceColumns
, REPLACE(f.update_referential_action_desc, '_', ' ') AS UpdateAction
, REPLACE(f.delete_referential_action_desc, '_', ' ') AS DeleteAction
FROM
sys.tables AS t
LEFT JOIN sys.foreign_keys AS f
ON f.parent_object_id = t.object_id
AND f.type = 'F'
LEFT JOIN sys.tables AS rt
ON f.referenced_object_id = rt.object_id
CROSS APPLY
(
SELECT
',' + QUOTENAME(COL_NAME(fc.parent_object_id, fc.parent_column_id))AS [text()]
FROM
sys.foreign_key_columns AS fc
WHERE
fc.constraint_object_id = f.object_id
ORDER BY
fc.constraint_column_id
FOR XML PATH('')
) Parent(Cols)
CROSS APPLY
(
SELECT
',' + QUOTENAME(COL_NAME(fc.referenced_object_id, fc.referenced_column_id)) AS [text()]
FROM
sys.foreign_key_columns AS fc
WHERE
fc.constraint_object_id = f.object_id
ORDER BY
fc.constraint_column_id
FOR XML PATH('')
) Reference(Cols)
)
SELECT
ParentTable AS TableName
, 'ALTER TABLE ' + ParentTable + ' DROP CONSTRAINT ' + ConstraintName AS DropCmd
, 'TRUNCATE TABLE ' + ParentTable AS TruncateCmd
, 'ALTER TABLE ' + ParentTable + ' ADD CONSTRAINT ' + ConstraintName + ' FOREIGN KEY('
+ ParentColumns + ') REFERENCES ' + ReferenceTable + ' (' + ReferenceColumns
+ ') ON UPDATE ' + UpdateAction
+ ' ON DELETE ' + DeleteAction COLLATE SQL_Latin1_General_CP1_CI_AS AS CreateCmd
INTO
#ForeignKeys
FROM
ForeignKeys
ORDER BY
1;
-- SELECT * FROM #ForeignKeys
DECLARE #TableName SYSNAME
DECLARE #Sql NVARCHAR(MAX)
-- Drop all constraints
DECLARE FkCursor CURSOR FOR
SELECT
TableName
, DropCmd
FROM
#ForeignKeys
WHERE
DropCmd IS NOT NULL
OPEN FkCursor
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #TableName + ' : ' + #sql
EXEC sp_executesql #Sql
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
END
CLOSE FkCursor
DEALLOCATE FkCursor
-- Truncate all tables
DECLARE FkCursor CURSOR FOR
SELECT
TableName
, TruncateCmd
FROM
#ForeignKeys
OPEN FkCursor
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #TableName + ' : ' + #sql
EXEC sp_executesql #Sql
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
END
CLOSE FkCursor
DEALLOCATE FkCursor
-- Create all foreign keys
DECLARE FkCursor CURSOR FOR
SELECT
TableName
, CreateCmd
FROM
#ForeignKeys
WHERE
CreateCmd IS NOT NULL
OPEN FkCursor
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #TableName + ' : ' + #sql
EXEC sp_executesql #Sql
FETCH NEXT FROM FkCursor INTO #TableName, #Sql
END
CLOSE FkCursor
DEALLOCATE FkCursor
DROP TABLE #ForeignKeys;
DECLARE #drop nvarchar(max) = N'',
#truncate nvarchar(max) = N'',
#create nvarchar(max) = N'';
;WITH x AS
(
SELECT id = f.[object_id],
cname = QUOTENAME(f.name),
ctable = QUOTENAME(OBJECT_SCHEMA_NAME(f.parent_object_id))
+ N'.' + QUOTENAME(OBJECT_NAME(f.parent_object_id)),
ccol = QUOTENAME(COL_NAME(fc.parent_object_id,fc.parent_column_id)),
rtable = QUOTENAME(OBJECT_SCHEMA_NAME(f.referenced_object_id))
+ N'.' + QUOTENAME(OBJECT_NAME(f.referenced_object_id)),
rcol = QUOTENAME(COL_NAME(fc.referenced_object_id,fc.referenced_column_id)),
ou = f.update_referential_action_desc COLLATE SQL_Latin1_General_CP1_CI_AS,
od = f.delete_referential_action_desc COLLATE SQL_Latin1_General_CP1_CI_AS
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.[object_id] = fc.constraint_object_id
-- where clause to leave out certain tables here
),
y AS
(
SELECT
d = CHAR(13) + CHAR(10) + N'ALTER TABLE ' + ctable + N' DROP CONSTRAINT ' + cname + ';',
c = CHAR(13) + CHAR(10) + N'ALTER TABLE ' + ctable + N' ADD CONSTRAINT ' + cname
+ ' FOREIGN KEY (' + STUFF((SELECT N',' + ccol FROM x AS x2
WHERE x2.id = x.id FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
+ N') REFERENCES ' + rtable + N'(' + STUFF((SELECT N',' + rcol FROM x AS x3
WHERE x3.id = x.id FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, '') + N')'
+ CASE WHEN od <> N'NO_ACTION' THEN
' ON DELETE ' + REPLACE(od, N'SET_', N'SET ') ELSE N'' END
+ CASE WHEN ou <> N'NO_ACTION' THEN
' ON UPDATE ' + REPLACE(ou, N'SET_', N'SET ') ELSE N'' END
FROM x
)
SELECT
#drop = #drop + d,
#create = #create + c
FROM y GROUP BY d,c;
SELECT #truncate = #truncate + CHAR(13) + CHAR(10) + N'TRUNCATE TABLE '
+ QUOTENAME(SCHEMA_NAME(schema_id)) + N'.' + QUOTENAME(name) + N';'
FROM sys.tables
-- where clause to leave out certain tables here
;
-- use results to text. Note that for 200 tables you won't be able to
-- manually inspect the entire script in Management Studio because it
-- will only show a certain number of characters depending on settings.
SELECT #drop;
SELECT #truncate;
SELECT #create;
-- when you are happy, uncomment these:
--EXEC sys.sp_executesql #drop;
--EXEC sys.sp_executesql #truncate;
--EXEC sys.sp_executesql #create;
Right click on the object(in the object explorer) and click Script as--> drop to. Use the same method and Script as--> Create to. This should give you the scripts for Dropping as well as creating all the objects in your database. Run them in the sequence you like.
Or if you have a lot of tables and objects, you can right click on the database--> go to tasks and click on Generate Scripts.

select all databases in sysobjects that have a table named 'mytable' regardless of schema?

For a given sql 2000 - 2008 server I want to find any table named dbo.[MyTable] on that server. In addition, how do I find all databases that have a table named [dbo].[MyTable] and [AnySchemaName].[MyTable]. Is there a simple sp_ command like spTables MyTable? Or 'sp_AllDatabaseTable [MyTable]'?
I want to print it out like:
ServerName Database SchemaName MyTable Date Created
----------- --------- ----------- --------- -------------
Thx
I really would prefer a solution that does not use either CURSORS nor sp_msforeachdb.
The solution below is gives you an idea, and you can adapt it to your own needs.
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
BEGIN TRY
SET NOCOUNT ON
SET DATEFORMAT DMY
SET DEADLOCK_PRIORITY NORMAL;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #log NVARCHAR(MAX)
,#vCrlf CHAR(2);
SELECT #log = ''
,#vCrlf = CHAR(13)+CHAR(10);
DECLARE #SQL NVARCHAR(MAX)
BEGIN TRY DROP TABLE #OBJECTS END TRY BEGIN CATCH END CATCH
CREATE TABLE #OBJECTS(
DB_ID INT,
OBJECT_ID INT,
S_NAME SYSNAME,
NAME SYSNAME,
ROW_COUNT INT,
STATISTICS_UPDATED DATETIME)
SELECT #SQL = '
SELECT db_id=db_id(),
o.object_id,
s_name=s.name,
o.name,
ddps.row_count
,[Statistics_Updated]=STATS_DATE(I.OBJECT_ID,I.INDEX_ID)
FROM sys.indexes AS i
INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s ON s.schema_id = o.schema_id
INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID
AND i.index_id = ddps.index_id
WHERE i.index_id < 2
AND o.is_ms_shipped = 0
'
set #SQL = (
SELECT STUFF(
(SELECT N' ' + ' USE ' + QUOTENAME(name) +';' + #vCrlf + #SQL + #vCrlf
FROM SYS.DATABASES SD
WHERE SD.STATE_DESC = 'ONLINE' -->Skips the database if it is not online
AND SD.COMPATIBILITY_LEVEL > 80
AND SD.database_id > 3 -- NO MASTER NOR TEMPDB NOR MODEL
FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
)
INSERT INTO #OBJECTS
( [db_id],
[object_id],
[s_name],
[name],
[row_count],
[Statistics_Updated]
)
EXECUTE MASTER.DBO.sp_executesql #SQL
SELECT * FROM #OBJECTS
--WHERE NAME = 'THE NAME THAT I AM LOOKING FOR'
END TRY
BEGIN CATCH
PRINT '--EXCEPTION WAS CAUGHT--' + CHAR(13) +
'THE ERROR NUMBER:' + COALESCE(CAST ( ERROR_NUMBER() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'SEVERITY: ' + COALESCE(CAST ( ERROR_SEVERITY() AS VARCHAR), 'NO INFO') + CHAR(13) +
'STATE: ' + COALESCE(CAST ( ERROR_STATE() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'PROCEDURE: ' + COALESCE(CAST ( COALESCE(ERROR_PROCEDURE(),'NO INFO') AS VARCHAR), 'NO INFO') + CHAR(13) +
'LINE NUMBER: ' + COALESCE(CAST ( ERROR_LINE() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'ERROR MESSAGE: '
PRINT CAST ( COALESCE(ERROR_MESSAGE(),'NO INFO') AS NTEXT)
END CATCH;
I prefer a set based approach:
Declare #TableName as Varchar(255)
Set #TableName = '<MyTableName>'
Declare #SQL as Varchar(max)
Select #SQL = Coalesce(#SQL + '
', '') +
CASE
WHEN Row_Number() Over (Order by Database_ID) = 1
THEN ''
ELSE
'UNION ALL '
END +
'SELECT
''' + d.Name + ''' as DatabaseName
, s.Name as SchemaName
, o.Name as TableName
FROM ' + d.Name +'.Sys.Objects o
INNER JOIN ' + d.Name + '.Sys.Schemas s
ON o.Schema_ID = s.Schema_ID
WHERE o.Name like ''' + #TableName + ''''
FROM sys.databases d
where d.Name not like 'ReportServer%'
and d.Name not like 'SSISPackageRegistry'
Print #SQL
EXEC(#SQL)
Of course, you can use sp_msforeachdb for this purpose but you need to remember that fhis function is neither documented nor officially supported. Also, sometimes it breaks. More about it here Making a more reliable and flexible sp_MSforeachdb
You can use this script to search table by name in all databases.
I took it from Find table in every database of SQL server
DECLARE #TableName VARCHAR(256)
SET #TableName='YOUR_TABLE_NAME'
DECLARE #DBName VARCHAR(256)
DECLARE #varSQL VARCHAR(512)
DECLARE #getDBName CURSOR
SET #getDBName = CURSOR FOR
SELECT name
FROM sys.databases
CREATE TABLE #TmpTable (DBName VARCHAR(256),
SchemaName VARCHAR(256),
TableName VARCHAR(256),
create_date date, modify_date date)
OPEN #getDBName
FETCH NEXT
FROM #getDBName INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #varSQL = 'USE ' + #DBName + ';
INSERT INTO #TmpTable
SELECT '''+ #DBName + ''' AS DBName,
SCHEMA_NAME(schema_id) AS SchemaName,
name AS TableName,
create_date, modify_date
FROM sys.tables
WHERE name LIKE ''%' + #TableName + '%''' --WHERE name = '' + #TableName + ''' /* if you want to search by exact table name*/
EXEC (#varSQL)
FETCH NEXT
FROM #getDBName INTO #DBName
END
CLOSE #getDBName
DEALLOCATE #getDBName
SELECT *
FROM #TmpTable
DROP TABLE #TmpTable
Also, you may want to read this Find table name in all objects of all databases
I'd have said
sp_msforeachdb 'Select * from Sysobjects where name=''MyTable'''
But you don't need to, sysobjects is in the master table and does it for all databases anyway.
You should be able find the other columns easily enough.

Programmatically copy indexes from one table to another in SQL Server

Basically the exact same question as in this question: How to copy indexes from one table to another in SQL Server, BUT, how do I do it programmatically in T-SQL, given a source table name and destination table name?
I.e. without knowing what table up front.
I can copy the basic structure
SELECT TOP (0) * INTO [BackupTable] FROM [OriginalTable]
But that doesn't copy indexes, constraints, triggers etc
I ideally would like a stored proc that looks something like:
spCloneTableStructure #ExistingTableName, #NewTableName
That copies the columns, primary keys and indexes
Anything like that exist? (note that I'm on SQL Server 2008 R2)
This is what I came up with. It works for me and copies all the stuff I care about.
CREATE PROCEDURE [dbo].[spCloneTableStructure]
#SourceSchema nvarchar(255),
#SourceTable nvarchar(255),
#DestinationSchema nvarchar(255),
#DestinationTable nvarchar(255),
#RecreateIfExists bit = 0
AS
BEGIN
/*
Clones an existing table to another table (without data)
Optionally drops and re-creates target table
Copies:
* Structure
* Primary key
* Indexes (including ASC/DESC, included columns, filters)
* Constraints (and unique constraints)
DOES NOT copy:
* Triggers
* File groups
* Probably a lot of other things
Note: Assumes that you name (unique) constraints with the table name in it (in order to not duplicate constraint names)
*/
SET NOCOUNT ON;
BEGIN TRANSACTION
--drop the table
if EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = #DestinationSchema AND TABLE_NAME = #DestinationTable)
BEGIN
if #RecreateIfExists = 1
BEGIN
exec('DROP TABLE [' + #DestinationSchema + '].[' + #DestinationTable + ']')
END
ELSE
RETURN
END
--create the table
exec('SELECT TOP (0) * INTO [' + #DestinationSchema + '].[' + #DestinationTable + '] FROM [' + #SourceSchema + '].[' + #SourceTable + ']')
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255)
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = #SourceSchema AND TABLE_NAME = #SourceTable AND CONSTRAINT_TYPE = 'PRIMARY KEY'
--create primary key
IF NOT #PKSchema IS NULL AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''
SELECT #PKColumns = #PKColumns + '[' + COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
where TABLE_NAME = #SourceTable and TABLE_SCHEMA = #SourceSchema AND CONSTRAINT_SCHEMA = #PKSchema AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED (' + #PKColumns + ')');
END
--create other indexes
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max)
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition FROM sys.indexes WHERE type = 2 and object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Unique nvarchar(255)
SET #Unique = CASE WHEN #IsUnique = 1 THEN ' UNIQUE ' ELSE '' END
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #KeyColumns = ''
SET #IncludedColumns = ''
select #KeyColumns = #KeyColumns + '[' + c.name + '] ' + CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END + ',' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal > 0
order by index_column_id
select #IncludedColumns = #IncludedColumns + '[' + c.name + '],' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']') and key_ordinal = 0
order by index_column_id
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = ' INCLUDE (' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + ')'
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = ''
ELSE
SET #FilterDefinition = 'WHERE ' + #FilterDefinition + ' '
if #IsUniqueConstraint = 0
exec('CREATE ' + #Unique + ' NONCLUSTERED INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition)
ELSE
BEGIN
SET #IndexName = REPLACE(#IndexName, #SourceTable, #DestinationTable)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [' + #IndexName + '] UNIQUE NONCLUSTERED (' + #KeyColumns + ')');
END
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
END;
CLOSE indexcursor;
DEALLOCATE indexcursor;
--create constraints
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max)
DECLARE constraintcursor CURSOR FOR
SELECT REPLACE(c.CONSTRAINT_NAME, #SourceTable, #DestinationTable), CHECK_CLAUSE from INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE t
INNER JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS c ON c.CONSTRAINT_SCHEMA = TABLE_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE TABLE_SCHEMA = #SourceSchema AND TABLE_NAME = #SourceTable
OPEN constraintcursor;
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
WHILE ##FETCH_STATUS = 0
BEGIN
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] WITH CHECK ADD CONSTRAINT [' + #ConstraintName + '] CHECK ' + #CheckClause)
exec('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] CHECK CONSTRAINT [' + #ConstraintName + ']')
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
END;
CLOSE constraintcursor;
DEALLOCATE constraintcursor;
COMMIT TRANSACTION
END
I have made some alterations to Gareth's work, which BTW works and I think is great. I wanted to include cloning the Triggers and copy the tables content as well. In essence "copy" as much of the table as best I can in one shot. I have included the whole piece of code. Remember this is not completely original, and I do not claim credit for any of Gareth's hard work. I hope this is useful for anyone interested.
CREATE PROCEDURE [dbo].[spCloneTableStructure]
#SourceSchema nvarchar(255)
, #SourceTable nvarchar(255)
, #DestinationSchema nvarchar(255)
, #DestinationTable nvarchar(255)
, #RecreateIfExists bit = 0
AS
BEGIN
/*
Clones an existing table to another table (without data)
Optionally drops and re-creates target table
Copies:
* Structure
* Primary key
* Indexes (including ASC/DESC, included columns, filters)
* Constraints (and unique constraints)
DOES NOT copy:
* Triggers (It seems to do this now)
* File groups
* Probably a lot of other things
Note: Assumes that you name (unique) constraints with the table name in it (in order to not duplicate constraint names)
*/
SET NOCOUNT ON;
BEGIN TRANSACTION
--drop the table
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = #DestinationSchema AND TABLE_NAME = #DestinationTable)
BEGIN
IF #RecreateIfExists = 1
BEGIN
EXEC('DROP TABLE [' + #DestinationSchema + '].[' + #DestinationTable + ']')
END
ELSE
BEGIN
RETURN
END
END
--create the table
EXEC('SELECT TOP (0) * INTO [' + #DestinationSchema + '].[' + #DestinationTable + '] FROM [' + #SourceSchema + '].[' + #SourceTable + ']')
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255)
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = #SourceSchema
AND TABLE_NAME = #SourceTable
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
-----------------------------------------------------------------------------------
DECLARE #SourceColumns int
DECLARE #DestinationColumns int
DECLARE #MyColumn int
SELECT #SourceColumns = count(*)
FROM information_schema.columns
WHERE TABLE_NAME = #SourceTable
AND TABLE_SCHEMA = #SourceSchema
SELECT #DestinationColumns = count(*)
FROM information_schema.columns
WHERE TABLE_NAME = #DestinationTable
AND TABLE_SCHEMA = #DestinationSchema
IF #SourceColumns = #DestinationColumns
BEGIN
DECLARE #FullSourceTable varchar(128)
DECLARE #FullDestinationTable varchar(128)
SET #FullSourceTable = #SourceSchema+'.'+#SourceTable
SET #FullDestinationTable = #DestinationSchema+'.'+#DestinationTable
DECLARE #MySQL varchar(MAX)
DECLARE #MyValues varchar(MAX)
SET #MyColumn = 2
SET #MySQL = 'INSERT INTO '+#FullDestinationTable+' ('
SET #MyValues = COL_NAME(OBJECT_ID(#FullSourceTable), 1) + ', '
WHILE #MyColumn <= #DestinationColumns --Change this back
BEGIN
SET #MyValues = #MyValues+ COL_NAME(OBJECT_ID(#FullSourceTable), #MyColumn) + ', '
SET #MyColumn = #MyColumn + 1
END
SELECT #MyValues = SUBSTRING(LTRIM(RTRIM(#MyValues)),1,DATALENGTH(LTRIM(RTRIM(#MyValues)))-1)
SET #MySQL = #MySQL+#MyValues+') '
SET #MySQL = #MySQL+' SELECT '+#MyValues+' FROM '+#FullSourceTable
--SELECT #MySQL
EXEC(#MySQL)
END
ELSE
BEGIN
RAISERROR('Number of Source and Destination Columns do not match. Cannot continue with copying content.',16,1)
END
-----------------------------------------------------------------------------------
--create primary key
IF NOT #PKSchema IS NULL
AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''
SELECT #PKColumns = #PKColumns + '[' + COLUMN_NAME + '],'
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = #SourceTable
AND TABLE_SCHEMA = #SourceSchema
AND CONSTRAINT_SCHEMA = #PKSchema
AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
EXEC('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED (' + #PKColumns + ')');
END
--create other indexes
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max)
-------------------------------------------------------------------------------
-- Cursor Start
-------------------------------------------------------------------------------
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition
FROM sys.indexes
WHERE type = 2
AND object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Unique nvarchar(255)
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #Unique = CASE WHEN #IsUnique = 1 THEN ' UNIQUE ' ELSE '' END
SET #KeyColumns = ''
SET #IncludedColumns = ''
SELECT #KeyColumns = #KeyColumns + '[' + c.name + '] ' + CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END + ','
FROM sys.index_columns ic
INNER JOIN sys.columns c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
WHERE index_id = #IndexId
AND ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
AND key_ordinal > 0
ORDER BY index_column_id
SELECT #IncludedColumns = #IncludedColumns + '[' + c.name + '],'
FROM sys.index_columns ic
INNER JOIN sys.columns c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
WHERE index_id = #IndexId
AND ic.object_id = object_id('[' + #SourceSchema + '].[' + #SourceTable + ']')
AND key_ordinal = 0
ORDER BY index_column_id
IF LEN(#KeyColumns) > 0
BEGIN
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
END
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = ' INCLUDE (' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + ')'
END
IF #FilterDefinition IS NULL
BEGIN
SET #FilterDefinition = ''
END
ELSE
BEGIN
SET #FilterDefinition = 'WHERE ' + #FilterDefinition + ' '
END
IF #IsUniqueConstraint = 0
BEGIN
EXEC('CREATE ' + #Unique + ' NONCLUSTERED INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition)
END
ELSE
BEGIN
SET #IndexName = REPLACE(#IndexName, #SourceTable, #DestinationTable)
EXEC('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [' + #IndexName + '] UNIQUE NONCLUSTERED (' + #KeyColumns + ')');
END
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
END;
CLOSE indexcursor;
DEALLOCATE indexcursor;
-------------------------------------------------------------------------------
-- Cursor END
-------------------------------------------------------------------------------
--create constraints
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max)
-------------------------------------------------------------------------------
-- Cursor START
-------------------------------------------------------------------------------
DECLARE constraintcursor CURSOR FOR
SELECT REPLACE(c.CONSTRAINT_NAME, #SourceTable, #DestinationTable), CHECK_CLAUSE
FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE t
INNER JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS c
ON c.CONSTRAINT_SCHEMA = TABLE_SCHEMA
AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE TABLE_SCHEMA = #SourceSchema
AND TABLE_NAME = #SourceTable
OPEN constraintcursor;
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] WITH CHECK ADD CONSTRAINT [' + #ConstraintName + '] CHECK ' + #CheckClause)
EXEC('ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] CHECK CONSTRAINT [' + #ConstraintName + ']')
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
END;
CLOSE constraintcursor;
DEALLOCATE constraintcursor;
-------------------------------------------------------------------------------
-- Cursor END
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Build Triggers on new table START
-------------------------------------------------------------------------------
DECLARE #TriggerType varchar(32)
DECLARE #CHeader varchar(255)
DECLARE #trigger_name varchar(128)
DECLARE #table_schema varchar(128)
DECLARE #table_name varchar(128)
DECLARE #isupdate tinyint
DECLARE #isdelete tinyint
DECLARE #isinsert tinyint
DECLARE #isafter tinyint
DECLARE #isinsteadof tinyint
DECLARE #disabled tinyint
DECLARE #TriggerCode varchar(MAX)
DECLARE db_cursor CURSOR FOR
SELECT so.name
,( SELECT TOP 1 SCHEMA_NAME(T1.schema_id)
FROM sys.tables AS T1
WHERE T1.name = OBJECT_NAME(parent_obj))
,OBJECT_NAME(parent_obj)
,OBJECTPROPERTY(so.id, 'ExecIsUpdateTrigger')
,OBJECTPROPERTY(so.id, 'ExecIsDeleteTrigger')
,OBJECTPROPERTY(so.id, 'ExecIsInsertTrigger')
,OBJECTPROPERTY(so.id, 'ExecIsAfterTrigger')
,OBJECTPROPERTY(so.id, 'ExecIsInsteadOfTrigger')
,OBJECTPROPERTY(so.id, 'ExecIsTriggerDisabled')
,LTRIM(RTRIM(c.[text]))
FROM sys.sysobjects AS so
INNER JOIN sys.objects o ON so.id = o.object_id
INNER JOIN sys.syscomments AS c ON o.object_id = c.id
WHERE so.type = 'TR'
AND OBJECT_NAME(parent_object_id) = #SourceTable
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #trigger_name, #table_schema, #table_name, #isupdate, #isdelete, #isinsert, #isafter, #isinsteadof, #disabled, #TriggerCode
WHILE ##FETCH_STATUS = 0
BEGIN
--SELECT #trigger_name, #table_schema, #table_name, #isupdate, #isdelete, #isinsert, #isafter, #isinsteadof, #disabled, #TriggerCode
SET #TriggerCode = LTRIM(RTRIM(REPLACE(#TriggerCode, CHAR(13)+CHAR(13)+CHAR(13), CHAR(13))))
SET #TriggerCode = LTRIM(RTRIM(REPLACE(#TriggerCode, CHAR(13)+CHAR(13), CHAR(13))))
-------------------------------------------------------------------------------
--Which one is first?
-------------------------------------------------------------------------------
DECLARE #MyStart tinyint
DECLARE #MyForStart tinyint
DECLARE #MyAfterStart tinyint
DECLARE #MyInsteadStart tinyint
SELECT #MyForStart = CHARINDEX('for',#TriggerCode)
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,CHARINDEX('for',#TriggerCode)-1, 4 )))
SELECT #MyAfterStart = CHARINDEX('after',#TriggerCode)
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,CHARINDEX('after',#TriggerCode)-1, 6 )))
SELECT #MyInsteadStart = CHARINDEX('instead',#TriggerCode)
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,CHARINDEX('Instead',#TriggerCode)-1, 8 )))
IF #MyAfterStart <> 0
AND #MyAfterStart < #MyForStart
BEGIN
SET #MyStart = #MyAfterStart
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,#MyStart-1, 6 )))
END
ELSE IF #MyInsteadStart <> 0
AND #MyInsteadStart < #MyForStart
BEGIN
SET #MyStart = #MyInsteadStart
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,#MyStart-1, 8 )))
END
ELSE IF #MyForStart <> 0
AND #MyForStart < #MyAfterStart
AND #MyForStart < #MyInsteadStart
BEGIN
SET #MyStart = #MyForStart
SELECT #TriggerType = LTRIM(RTRIM(SUBSTRING(#TriggerCode,#MyStart-1, 4 )))
END
-------------------------------------------------------------------------------
--Build the correct header and append it to the create trigger code then run it
-------------------------------------------------------------------------------
IF #TriggerType LIKE '%FOR%'
BEGIN
SET #CHeader = 'CREATE TRIGGER ['+#DestinationSchema+'].['+#trigger_name+'] ON ['+#DestinationSchema+'].['+#DestinationTable+']'
--print #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('FOR',#TriggerCode)-1,DATALENGTH(#TriggerCode))
SET #TriggerCode = #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('for',#TriggerCode)-1,DATALENGTH(#TriggerCode))
EXEC(#TriggerCode)
END
ELSE IF #TriggerType LIKE '%AFTER%'
BEGIN
SET #CHeader = 'CREATE TRIGGER ['+#DestinationSchema+'].['+#trigger_name+'] ON ['+#DestinationSchema+'].['+#DestinationTable+']'
--print #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('AFTER',#TriggerCode)-1,DATALENGTH(#TriggerCode))
SET #TriggerCode = #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('after',#TriggerCode)-1,DATALENGTH(#TriggerCode))
EXEC(#TriggerCode)
END
ELSE IF #TriggerType LIKE '%INSTEAD%'
BEGIN
SET #CHeader = 'CREATE TRIGGER ['+#DestinationSchema+'].['+#trigger_name+'] ON ['+#DestinationSchema+'].['+#DestinationTable+']'
--print #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('INSTEAD',#TriggerCode)-1,DATALENGTH(#TriggerCode))
SET #TriggerCode = #CHeader+char(13)+SUBSTRING(#TriggerCode,CHARINDEX('instead',#TriggerCode)-1,DATALENGTH(#TriggerCode))
EXEC(#TriggerCode)
END
FETCH NEXT FROM db_cursor INTO #trigger_name, #table_schema, #table_name, #isupdate, #isdelete, #isinsert, #isafter, #isinsteadof, #disabled, #TriggerCode
END
CLOSE db_cursor
DEALLOCATE db_cursor
COMMIT TRANSACTION
END
Thanks Gareth. That works. I have altered to work across databases:
CREATE PROCEDURE [dbo].[spCloneDatabaseTableStructurev3]
#SourceDatabase nvarchar(max),
#SourceSchema nvarchar(max),
#SourceTable nvarchar(max),
#DestinationDatabase nvarchar(max),
#DestinationSchema nvarchar(max),
#DestinationTable nvarchar(max),
#RecreateIfExists bit = 0
AS
BEGIN
/*
Clones an existing table to another table (without data)
Optionally drops and re-creates target table
Copies:
* Structure
* Primary key
* Indexes (including ASC/DESC, included columns, filters)
* Constraints (and unique constraints)
DOES NOT copy:
* Triggers
* File groups
* Probably a lot of other things
Note: Assumes that you name (unique) constraints with the table name in it (in order to not duplicate constraint names)
*/
declare #sql nvarchar(max)
SET NOCOUNT ON;
BEGIN TRANSACTION
set #sql = '
declare #RecreateIfExists bit = ' + convert(varchar(max),#RecreateIfExists) + '
--drop the table
if EXISTS (SELECT * FROM [' + #DestinationDatabase + '].INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ''' + #DestinationSchema + ''' AND TABLE_NAME = ''' + #DestinationTable + ''')
BEGIN
if #RecreateIfExists = 1
BEGIN
DROP TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + ']
END
ELSE
RETURN
END
--create the table
SELECT TOP (0) * INTO [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] FROM [' + #SourceDatabase + '].[' + #SourceSchema + '].[' + #SourceTable + ']
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255)
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME FROM [' + #SourceDatabase + '].INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = ''' + #SourceSchema + ''' AND TABLE_NAME = ''' + #SourceTable + ''' AND CONSTRAINT_TYPE = ''PRIMARY KEY''
--create primary key
IF NOT #PKSchema IS NULL AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''''
SELECT #PKColumns = #PKColumns + ''['' + COLUMN_NAME + ''],''
FROM [' + #SourceDatabase + '].INFORMATION_SCHEMA.KEY_COLUMN_USAGE
where TABLE_NAME = ''' + #SourceTable + ''' and TABLE_SCHEMA = ''' + #SourceSchema + ''' AND CONSTRAINT_SCHEMA = #PKSchema AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED ('' + #PKColumns + '')'')
END
--create other indexes
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max)
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition FROM sys.indexes WHERE type = 2 and object_id = object_id(''[' + #SourceSchema + '].[' + #SourceTable + ']'')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Unique nvarchar(255)
SET #Unique = CASE WHEN #IsUnique = 1 THEN '' UNIQUE '' ELSE '''' END
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #KeyColumns = ''''
SET #IncludedColumns = ''''
select #KeyColumns = #KeyColumns + ''['' + c.name + ''] '' + CASE WHEN is_descending_key = 1 THEN ''DESC'' ELSE ''ASC'' END + '','' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id(''[' + #SourceSchema + '].[' + #SourceTable + ']'') and key_ordinal > 0
order by index_column_id
select #IncludedColumns = #IncludedColumns + ''['' + c.name + ''],'' from sys.index_columns ic
inner join sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
where index_id = #IndexId and ic.object_id = object_id(''[' + #SourceSchema + '].[' + #SourceTable + ']'') and key_ordinal = 0
order by index_column_id
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = '' INCLUDE ('' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + '')''
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = ''''
ELSE
SET #FilterDefinition = ''WHERE '' + #FilterDefinition + '' ''
if #IsUniqueConstraint = 0
exec(''CREATE '' + #Unique + '' NONCLUSTERED INDEX ['' + #IndexName + ''] ON [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ('' + #KeyColumns + '')'' + #IncludedColumns + #FilterDefinition)
ELSE
BEGIN
SET #IndexName = REPLACE(#IndexName, ''' + #SourceTable + ''', ''' + #DestinationTable + ''')
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT ['' + #IndexName + ''] UNIQUE NONCLUSTERED ('' + #KeyColumns + '')'')
END
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
END;
CLOSE indexcursor;
DEALLOCATE indexcursor;
--create constraints
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max)
DECLARE constraintcursor CURSOR FOR
SELECT REPLACE(c.CONSTRAINT_NAME, ''' + #SourceTable + ''', ''' + #DestinationTable + '''), CHECK_CLAUSE from [' + #SourceDatabase + '].INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE t
INNER JOIN [' + #SourceDatabase + '].INFORMATION_SCHEMA.CHECK_CONSTRAINTS c ON c.CONSTRAINT_SCHEMA = TABLE_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE TABLE_SCHEMA = ''' + #SourceSchema + ''' AND TABLE_NAME = ''' + #SourceTable + '''
OPEN constraintcursor;
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
WHILE ##FETCH_STATUS = 0
BEGIN
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] WITH CHECK ADD CONSTRAINT ['' + #ConstraintName + ''] CHECK '' + #CheckClause)
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] CHECK CONSTRAINT ['' + #ConstraintName + '']'')
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
END;
CLOSE constraintcursor;
DEALLOCATE constraintcursor;'
exec(#sql)
COMMIT TRANSACTION
END
To give you an idea of what's involved (and why you should use SMO for this as mentioned in comments):
Get list of indexes from sys.indexes based on the object_ID of the source table
This includes other info like UNIQUE, PK, IGNORE_DUP_KEY, FILL_FACTOR, PADDED, DISABLED, ROW LOCKS, PAGE LOCKS which will all need to be coded separately in your dynamic SQL
Get list of all key fields (and their order, and if they are ASC or DESC) for each index from sys.index_columns. This will involve JOINing sys.columns for the names since they are all column IDs
Get list of included fields from sys.index_columns
Get a list of filters for each index from sys.indexes
Now translate all the above data into valid SQL scripts to execute on the target table.
For efficiency you should also script out the clustered index first and run it, since it will take longer to build a cluster if there are already non-clustered indexes in place.
Thanks Gareth. Good work! I needed a TSQL script which works across databases. Basicly what F_Face did. I've adjusted F_Face modification because there is still a hard coded database name and some statements are relying on that.
Anyway, I agree to all the comments that this isn't the way a deep structure copy of a table should be done. Use SMO via PowerShell via xp_cmdshell via TSQL to do it in a propper way would be my suggestion. In that way SMO is taking care that everything is copied and that next SQL Server generation works as well with it.
This mentioned, here the code:
--If the SP exists, we do nothing. If we would drop it, we would loose security settings.
--If the SP doesn't exist, create a dummy SP to be able to use ALTER PROCEDURE in both cases.
DECLARE #spName varchar(255)
SET #spName='spCloneTableStructure'
IF object_id(#spName) IS NULL --does the SP exist?
EXEC ('CREATE PROCEDURE dbo.'+#spName+' AS SELECT 1') --create dummy sp
GO
ALTER PROCEDURE [dbo].[spCloneTableStructure]
#SourceDatabase nvarchar(max),
#SourceSchema nvarchar(max),
#SourceTable nvarchar(max),
#DestinationDatabase nvarchar(max),
#DestinationSchema nvarchar(max),
#DestinationTable nvarchar(max),
#RecreateIfExists bit = 0
AS
BEGIN
/*
Clones an existing table to another table (without data)
Optionally drops and re-creates target table
Copies:
* Structure
* Primary key
* Indexes (including ASC/DESC, included columns, filters)
* Constraints (and unique constraints)
DOES NOT copy:
* Triggers
* File groups
* Probably a lot of other things
Note: Assumes that you name (unique) constraints with the table name in it (in order to not duplicate constraint names)
*/
DECLARE #sql NVARCHAR(MAX)
SET NOCOUNT ON;
BEGIN TRANSACTION
set #sql =
'DECLARE #RecreateIfExists bit = ' + convert(varchar(max),#RecreateIfExists) + '
--drop the table
if EXISTS (SELECT * FROM [' + #DestinationDatabase + '].INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = ''' + #DestinationSchema + '''
AND TABLE_NAME = ''' + #DestinationTable + ''')
BEGIN
IF #RecreateIfExists = 1
BEGIN
DROP TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + ']
END
ELSE
RETURN
END
--create the table
SELECT TOP (0) * INTO [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + ']
FROM [' + #SourceDatabase + '].[' + #SourceSchema + '].[' + #SourceTable + ']
DECLARE #PKSchema nvarchar(255), #PKName nvarchar(255)
SELECT TOP 1 #PKSchema = CONSTRAINT_SCHEMA, #PKName = CONSTRAINT_NAME
FROM [' + #SourceDatabase + '].INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = ''' + #SourceSchema + '''
AND TABLE_NAME = ''' + #SourceTable + '''
AND CONSTRAINT_TYPE = ''PRIMARY KEY''
--create primary key
IF NOT #PKSchema IS NULL AND NOT #PKName IS NULL
BEGIN
DECLARE #PKColumns nvarchar(MAX)
SET #PKColumns = ''''
SELECT #PKColumns = #PKColumns + ''['' + COLUMN_NAME + ''],''
FROM [' + #SourceDatabase + '].INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = ''' + #SourceTable + '''
AND TABLE_SCHEMA = ''' + #SourceSchema + '''
AND CONSTRAINT_SCHEMA = #PKSchema
AND CONSTRAINT_NAME= #PKName
ORDER BY ORDINAL_POSITION
SET #PKColumns = LEFT(#PKColumns, LEN(#PKColumns) - 1)
EXEC(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + ']
ADD CONSTRAINT [PK_' + #DestinationTable + '] PRIMARY KEY CLUSTERED ('' + #PKColumns + '')'')
END
--create other indexes
DECLARE #IndexId int, #IndexName nvarchar(255), #IsUnique bit, #IsUniqueConstraint bit, #FilterDefinition nvarchar(max)
DECLARE indexcursor CURSOR FOR
SELECT index_id, name, is_unique, is_unique_constraint, filter_definition
FROM ['+#SourceDatabase+'].sys.indexes
WHERE type = 2
AND object_id = object_id(''['+#SourceDatabase+'].[' + #SourceSchema + '].[' + #SourceTable + ']'')
OPEN indexcursor;
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Unique nvarchar(255)
SET #Unique = CASE WHEN #IsUnique = 1 THEN '' UNIQUE '' ELSE '''' END
DECLARE #KeyColumns nvarchar(max), #IncludedColumns nvarchar(max)
SET #KeyColumns = ''''
SET #IncludedColumns = ''''
SELECT #KeyColumns = #KeyColumns + ''['' + c.name + ''] '' + CASE WHEN is_descending_key = 1 THEN ''DESC'' ELSE ''ASC'' END + '',''
FROM ['+#SourceDatabase+'].sys.index_columns ic
INNER JOIN ['+#SourceDatabase+'].sys.columns c ON c.object_id = ic.object_id and c.column_id = ic.column_id
WHERE index_id = #IndexId
AND ic.object_id = object_id(''['+#SourceDatabase+'].[' + #SourceSchema + '].[' + #SourceTable + ']'')
AND key_ordinal > 0
ORDER BY index_column_id
SELECT #IncludedColumns = #IncludedColumns + ''['' + c.name + ''],'' from ['+#SourceDatabase+'].sys.index_columns ic
INNER JOIN ['+#SourceDatabase+'].sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
WHERE index_id = #IndexId
AND ic.object_id = object_id(''['+#SourceDatabase+'].[' + #SourceSchema + '].[' + #SourceTable + ']'')
AND key_ordinal = 0
ORDER BY index_column_id
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1)
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = '' INCLUDE ('' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + '')''
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = ''''
ELSE
SET #FilterDefinition = ''WHERE '' + #FilterDefinition + '' ''
if #IsUniqueConstraint = 0
exec(''CREATE '' + #Unique + '' NONCLUSTERED INDEX ['' + #IndexName + ''] ON [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ('' + #KeyColumns + '')'' + #IncludedColumns + #FilterDefinition)
ELSE
BEGIN
SET #IndexName = REPLACE(#IndexName, ''' + #SourceTable + ''', ''' + #DestinationTable + ''')
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT ['' + #IndexName + ''] UNIQUE NONCLUSTERED ('' + #KeyColumns + '')'')
END
FETCH NEXT FROM indexcursor INTO #IndexId, #IndexName, #IsUnique, #IsUniqueConstraint, #FilterDefinition;
END;
CLOSE indexcursor;
DEALLOCATE indexcursor;
--create constraints
DECLARE #ConstraintName nvarchar(max), #CheckClause nvarchar(max)
DECLARE constraintcursor CURSOR FOR
SELECT REPLACE(c.CONSTRAINT_NAME, ''' + #SourceTable + ''', ''' + #DestinationTable + '''), CHECK_CLAUSE
FROM [' + #SourceDatabase + '].INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE t
INNER JOIN [' + #SourceDatabase + '].INFORMATION_SCHEMA.CHECK_CONSTRAINTS c ON c.CONSTRAINT_SCHEMA = TABLE_SCHEMA AND c.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE TABLE_SCHEMA = ''' + #SourceSchema + '''
AND TABLE_NAME = ''' + #SourceTable + '''
OPEN constraintcursor;
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
WHILE ##FETCH_STATUS = 0
BEGIN
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] WITH CHECK ADD CONSTRAINT ['' + #ConstraintName + ''] CHECK '' + #CheckClause)
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] CHECK CONSTRAINT ['' + #ConstraintName + '']'')
FETCH NEXT FROM constraintcursor INTO #ConstraintName, #CheckClause;
END;
CLOSE constraintcursor;
DEALLOCATE constraintcursor;'
--PRINT SUBSTRING(#sql, 0, 4000)
--PRINT SUBSTRING(#sql, 4000, 8000)
EXEC(#sql)
COMMIT TRANSACTION
END
This is quick and dirty mod, based on this question: Generate CREATE scripts for a list of indexes but should get you most of the way there. You could do what you are already doing to clone the structure, and you a version of this proc to do they indexes and then modify as necessary:
CREATE sp_CloneIndex #OldTableName varchar(50), #NewTableName varchar(50)
AS
WITH indexCTE AS
(
SELECT DISTINCT
i.index_id, i.name, i.object_id
FROM
sys.indexes i
INNER JOIN
sys.index_columns ic
ON i.index_id = ic.index_id AND i.object_id = ic.object_id
WHERE
EXISTS (SELECT * FROM sys.columns c WHERE c.column_id = ic.column_id AND c.object_id = ic.object_id)
),
indexCTE2 AS
(
SELECT
indexCTE.name 'IndexName',
OBJECT_NAME(indexCTE.object_ID) 'TableName',
CASE indexCTE.index_id
WHEN 1 THEN 'CLUSTERED'
ELSE 'NONCLUSTERED'
END AS 'IndexType',
(SELECT DISTINCT c.name + ','
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
) ixcols,
ISNULL(
(SELECT DISTINCT c.name + ','
FROM
sys.columns c
INNER JOIN
sys.index_columns ic
ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1
WHERE
indexCTE.OBJECT_ID = ic.object_id
AND indexCTE.index_id = ic.index_id
FOR XML PATH('')
), '') includedcols
FROM
indexCTE
)
SELECT
'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + #NewTableName +
'(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) +
CASE LEN(includedcols)
WHEN 0 THEN ')'
ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')'
END
FROM
indexCTE2
where tablename = #OldTableName
ORDER BY
TableName, IndexName
Here is my version. The destination table and schema are the same like the source with something added at the end in my case _STG. You can add something at the end using #NameAdd NVARCHAR(128) variable. I did it this way to avoid sql injection. In my version no outside provided text is executed.
IF EXISTS(SELECT * FROM sys.objects WHERE type = 'P' AND name='uspCloneTableStructure')
BEGIN
DROP PROCEDURE [dbo].[uspCloneTableStructure]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[uspCloneTableStructure]
#inSourceSchema nvarchar(128),
#inSourceTable nvarchar(128),
#RecreateTable bit = 0,
#RecreateIndexes bit = 0
AS
BEGIN
SET NOCOUNT ON;
DECLARE #RecID INT
,#RecCount INT
,#ExecuteCMD NVARCHAR(MAX) = ''
,#DateTime VARCHAR(100)
,#SourceSchema NVARCHAR(128)
,#SourceTable NVARCHAR(128)
,#DestinationSchema NVARCHAR(128)
,#DestinationTable NVARCHAR(128)
,#NameAdd NVARCHAR(128) = N'_STG';
BEGIN TRANSACTION;
BEGIN TRY;
SET XACT_ABORT ON;
SELECT #SourceSchema = s.name
,#SourceTable = t.name
,#DestinationSchema = s.name
,#DestinationTable = t.name + #NameAdd
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
WHERE s.name = #inSourceSchema
AND t.name = #inSourceTable;
--drop the table
if #RecreateTable = 1 AND #DestinationSchema IS NOT NULL AND #DestinationTable IS NOT NULL
BEGIN
SET #ExecuteCMD ='IF EXISTS (SELECT * FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
WHERE s.name = ''' + #DestinationSchema + ''' AND t.name = ''' + #DestinationTable + ''')
DROP TABLE [' + #DestinationSchema + '].[' + #DestinationTable + ']
SELECT TOP (0) * INTO [' + #DestinationSchema + '].[' + #DestinationTable + '] FROM [' + #SourceSchema + '].[' + #SourceTable + ']';
SELECT #DateTime = CONVERT(VARCHAR(100),GETDATE(),(121));
RAISERROR('--Creating table: %s at: %s ',0,1,#DestinationTable,#DateTime) WITH NOWAIT;
PRINT #ExecuteCMD;
EXECUTE sp_executesql #ExecuteCMD;
END;
IF #RecreateIndexes = 1
BEGIN
--create other indexes
DECLARE #IndexId INT
,#IndexName NVARCHAR(128)
,#FilterDefinition NVARCHAR(MAX)
,#IsPrimaryKey BIT
,#Unique NVARCHAR(128)
,#Clustered NVARCHAR(128)
,#DataCompression NVARCHAR(60)
,#KeyColumns NVARCHAR(MAX)
,#IncludedColumns NVARCHAR(MAX);
IF OBJECT_ID('tempdb.dbo.#Indexes') IS NOT NULL
BEGIN
DROP TABLE dbo.#Indexes;
END;
CREATE TABLE dbo.#Indexes
(
[RecID] INT IDENTITY(1, 1) PRIMARY KEY
,IndexId INT
,IndexName NVARCHAR(128)
,IsUnique BIT
,FilterDefinition NVARCHAR(MAX)
,IsClustered INT
,IsPrimaryKey BIT
,DataCompression NVARCHAR(60)
);
INSERT INTO dbo.#Indexes
( IndexId
,IndexName
,IsUnique
,FilterDefinition
,IsClustered
,IsPrimaryKey
,DataCompression )
SELECT i.index_id
,i.name
,i.is_unique
,i.filter_definition
,i.index_id
,i.is_primary_key
,sp.data_compression_desc
FROM sys.indexes AS i
INNER JOIN sys.tables AS t
ON t.[object_id] = i.[object_id]
INNER JOIN sys.schemas AS s
ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.partitions AS sp
ON i.[object_id] = sp.[object_id]
AND i.[index_id] = sp.[index_id]
AND sp.partition_number = 1
WHERE i.type <>0
AND s.name = #SourceSchema
AND t.name = #SourceTable;
SELECT #RecCount = COUNT(*) FROM dbo.#Indexes;
SET #RecID = 1;
WHILE (#RecID <= #RecCount)
BEGIN
SELECT #IndexId = IndexId
,#IndexName = IndexName
,#Unique = CASE WHEN IsUnique = 1 THEN ' UNIQUE ' ELSE '' END
,#FilterDefinition = FilterDefinition
,#Clustered = CASE WHEN IsClustered = 1 THEN ' CLUSTERED ' ELSE ' NONCLUSTERED ' END
,#IsPrimaryKey = IsPrimaryKey
,#DataCompression = DataCompression
,#KeyColumns = ''
,#IncludedColumns = ''
FROM dbo.#Indexes
WHERE [RecID] = #RecID;
SELECT #KeyColumns = #KeyColumns + '[' + c.name + '] '
+ CASE WHEN is_descending_key = 1 THEN 'DESC'
ELSE 'ASC'
END + ','
FROM sys.index_columns ic
INNER JOIN sys.columns c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
INNER JOIN sys.tables AS t
ON t.object_id = c.object_id
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
WHERE ic.index_id = #IndexId
AND s.name = #SourceSchema
AND t.name = #SourceTable
AND key_ordinal > 0
ORDER BY index_column_id;
SELECT #IncludedColumns = #IncludedColumns + '[' + c.name + '],'
FROM sys.index_columns ic
INNER JOIN sys.columns c
ON c.object_id = ic.object_id
AND c.column_id = ic.column_id
INNER JOIN sys.tables AS t
ON t.object_id = c.object_id
INNER JOIN sys.schemas AS s
ON s.schema_id = t.schema_id
WHERE ic.index_id = #IndexId
AND s.name = #SourceSchema
AND t.name = #SourceTable
AND key_ordinal = 0
ORDER BY index_column_id;
IF LEN(#KeyColumns) > 0
SET #KeyColumns = LEFT(#KeyColumns, LEN(#KeyColumns) - 1);
IF LEN(#IncludedColumns) > 0
BEGIN
SET #IncludedColumns = ' INCLUDE (' + LEFT(#IncludedColumns, LEN(#IncludedColumns) - 1) + ')';
END
IF #FilterDefinition IS NULL
SET #FilterDefinition = '';
ELSE
SET #FilterDefinition = 'WHERE ' + #FilterDefinition + ' ';
--create the index or PK
IF #IsPrimaryKey = 1
SET #ExecuteCMD = 'ALTER TABLE [' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT [' + #IndexName + #NameAdd + '] PRIMARY KEY CLUSTERED (' + #KeyColumns + ') WITH (SORT_IN_TEMPDB=ON,DATA_COMPRESSION='+#DataCompression+');';
ELSE
SET #ExecuteCMD = 'CREATE ' + #Unique + #Clustered + ' INDEX [' + #IndexName + '] ON [' + #DestinationSchema + '].[' + #DestinationTable + '] (' + #KeyColumns + ')' + #IncludedColumns + #FilterDefinition + ' WITH (SORT_IN_TEMPDB=ON,DATA_COMPRESSION='+#DataCompression+');';
SELECT #DateTime = CONVERT(VARCHAR(100),GETDATE(),(121));
RAISERROR('--Creating index: %s%s at: %s ',0,1,#IndexName,#NameAdd,#DateTime) WITH NOWAIT;
PRINT #ExecuteCMD;
EXECUTE sp_executesql #ExecuteCMD;
SET #RecID = #RecID + 1;
END;/*While loop*/
END;
COMMIT TRAN;
SET XACT_ABORT OFF;
END TRY BEGIN CATCH;
SET XACT_ABORT OFF;
IF (XACT_STATE() != 0)
BEGIN;
ROLLBACK TRANSACTION;
END;
THROW;
-- RETURN;
END CATCH;
END
GO
Another procedure to clone ONLY foreign keys (Note that referenced table must already exists, obviously).
CREATE PROCEDURE [dbo].[spCloneFKStructure]
#SourceDatabase nvarchar(max),
#SourceSchema nvarchar(max),
#SourceTable nvarchar(max),
#DestinationDatabase nvarchar(max),
#DestinationSchema nvarchar(max),
#DestinationTable nvarchar(max)
AS
BEGIN
declare #sql nvarchar(max)
SET NOCOUNT ON;
BEGIN TRANSACTION
set #sql = '
--create foreign keys
DECLARE #ConstraintName nvarchar(max),#ColName nvarchar(max),#RefTable nvarchar(max),#RefColName nvarchar(max)
DECLARE fkcursor CURSOR FOR
select a.name,c.name,object_name(b.referenced_object_id,db_id(''' + #SourceDatabase + ''')),d.name
from [' + #SourceDatabase + '].sys.foreign_keys a
join [' + #SourceDatabase + '].sys.foreign_key_columns b on a.object_id=b.constraint_object_id
join [' + #SourceDatabase + '].sys.columns c on b.parent_column_id = c.column_id and a.parent_object_id=c.object_id
join [' + #SourceDatabase + '].sys.columns d on b.referenced_column_id = d.column_id and a.referenced_object_id = d.object_id
where
object_name(a.parent_object_id,db_id(''' + #SourceDatabase + ''')) = ''' + #SourceTable + ''' order by c.name
OPEN fkcursor;
FETCH NEXT FROM fkcursor INTO #ConstraintName, #ColName, #RefTable, #RefColName;
WHILE ##FETCH_STATUS = 0
BEGIN
exec(''ALTER TABLE [' + #DestinationDatabase + '].[' + #DestinationSchema + '].[' + #DestinationTable + '] ADD CONSTRAINT ['' + #ConstraintName + ''] FOREIGN KEY ('' + #ColName + '') REFERENCES '' + #RefTable + ''('' + #RefColName + '')'')
FETCH NEXT FROM fkcursor INTO #ConstraintName, #ColName, #RefTable, #RefColName;
END;
CLOSE fkcursor;
DEALLOCATE fkcursor;'
exec(#sql)
COMMIT TRANSACTION
END

In SQL Server, how do I generate a CREATE TABLE statement for a given table?

I've spent a good amount of time coming up with solution to this problem, so in the spirit of this post, I'm posting it here, since I think it might be useful to others.
If anyone has a better script, or anything to add, please post it.
Edit: Yes guys, I know how to do it in Management Studio - but I needed to be able to do it from within another application.
I've modified the version above to run for all tables and support new SQL 2005 data types. It also retains the primary key names. Works only on SQL 2005 (using cross apply).
select 'create table [' + so.name + '] (' + o.list + ')' + CASE WHEN tc.Constraint_Name IS NULL THEN '' ELSE 'ALTER TABLE ' + so.Name + ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ')' END
from sysobjects so
cross apply
(SELECT
' ['+column_name+'] ' +
data_type + case data_type
when 'sql_variant' then ''
when 'text' then ''
when 'ntext' then ''
when 'xml' then ''
when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
else coalesce('('+case when character_maximum_length = -1 then 'MAX' else cast(character_maximum_length as varchar) end +')','') end + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=so.name
and name=column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(so.name) as varchar) + ',' +
cast(ident_incr(so.name) as varchar) + ')'
else ''
end + ' ' +
(case when UPPER(IS_NULLABLE) = 'NO' then 'NOT ' else '' end ) + 'NULL ' +
case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT ELSE '' END + ', '
from information_schema.columns where table_name = so.name
order by ordinal_position
FOR XML PATH('')) o (list)
left join
information_schema.table_constraints tc
on tc.Table_name = so.Name
AND tc.Constraint_Type = 'PRIMARY KEY'
cross apply
(select '[' + Column_Name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY
ORDINAL_POSITION
FOR XML PATH('')) j (list)
where xtype = 'U'
AND name NOT IN ('dtproperties')
Update: Added handling of the XML data type
Update 2: Fixed cases when 1) there is multiple tables with the same name but with different schemas, 2) there is multiple tables having PK constraint with the same name
Here's the script that I came up with. It handles Identity columns, default values, and primary keys. It does not handle foreign keys, indexes, triggers, or any other clever stuff. It works on SQLServer 2000, 2005 and 2008.
declare #schema varchar(100), #table varchar(100)
set #schema = 'dbo' -- set schema name here
set #table = 'MyTable' -- set table name here
declare #sql table(s varchar(1000), id int identity)
-- create statement
insert into #sql(s) values ('create table [' + #table + '] (')
-- column list
insert into #sql(s)
select
' ['+column_name+'] ' +
data_type + coalesce('('+cast(character_maximum_length as varchar)+')','') + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=#table
and name=column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(#table) as varchar) + ',' +
cast(ident_incr(#table) as varchar) + ')'
else ''
end + ' ' +
( case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
coalesce('DEFAULT '+COLUMN_DEFAULT,'') + ','
from INFORMATION_SCHEMA.COLUMNS where table_name = #table AND table_schema = #schema
order by ordinal_position
-- primary key
declare #pkname varchar(100)
select #pkname = constraint_name from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
where table_name = #table and constraint_type='PRIMARY KEY'
if ( #pkname is not null ) begin
insert into #sql(s) values(' PRIMARY KEY (')
insert into #sql(s)
select ' ['+COLUMN_NAME+'],' from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
where constraint_name = #pkname
order by ordinal_position
-- remove trailing comma
update #sql set s=left(s,len(s)-1) where id=##identity
insert into #sql(s) values (' )')
end
else begin
-- remove trailing comma
update #sql set s=left(s,len(s)-1) where id=##identity
end
-- closing bracket
insert into #sql(s) values( ')' )
-- result!
select s from #sql order by id
There is a Powershell script buried in the msdb forums that will script all the tables and related objects:
# Script all tables in a database
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
| out-null
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') '<Servername>'
$db = $s.Databases['<Database>']
$scrp = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($s)
$scrp.Options.AppendToFile = $True
$scrp.Options.ClusteredIndexes = $True
$scrp.Options.DriAll = $True
$scrp.Options.ScriptDrops = $False
$scrp.Options.IncludeHeaders = $False
$scrp.Options.ToFileOnly = $True
$scrp.Options.Indexes = $True
$scrp.Options.WithDependencies = $True
$scrp.Options.FileName = 'C:\Temp\<Database>.SQL'
foreach($item in $db.Tables) { $tablearray+=#($item) }
$scrp.Script($tablearray)
Write-Host "Scripting complete"
Support for schemas:
This is an updated version that amends the great answer from David, et al. Added is support for named schemas. It should be noted this may break if there's actually tables of the same name present within various schemas. Another improvement is the use of the official QuoteName() function.
SELECT
t.TABLE_CATALOG,
t.TABLE_SCHEMA,
t.TABLE_NAME,
'create table '+QuoteName(t.TABLE_SCHEMA)+'.' + QuoteName(so.name) + ' (' + LEFT(o.List, Len(o.List)-1) + '); '
+ CASE WHEN tc.Constraint_Name IS NULL THEN ''
ELSE
'ALTER TABLE ' + QuoteName(t.TABLE_SCHEMA)+'.' + QuoteName(so.name)
+ ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + '); '
END as 'SQL_CREATE_TABLE'
FROM sysobjects so
CROSS APPLY (
SELECT
' ['+column_name+'] '
+ data_type
+ case data_type
when 'sql_variant' then ''
when 'text' then ''
when 'ntext' then ''
when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
else
coalesce(
'('+ case when character_maximum_length = -1
then 'MAX'
else cast(character_maximum_length as varchar) end
+ ')','')
end
+ ' '
+ case when exists (
SELECT id
FROM syscolumns
WHERE
object_name(id) = so.name
and name = column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(so.name) as varchar) + ',' +
cast(ident_incr(so.name) as varchar) + ')'
else ''
end
+ ' '
+ (case when IS_NULLABLE = 'No' then 'NOT ' else '' end)
+ 'NULL '
+ case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT
ELSE ''
END
+ ',' -- can't have a field name or we'll end up with XML
FROM information_schema.columns
WHERE table_name = so.name
ORDER BY ordinal_position
FOR XML PATH('')
) o (list)
LEFT JOIN information_schema.table_constraints tc on
tc.Table_name = so.Name
AND tc.Constraint_Type = 'PRIMARY KEY'
LEFT JOIN information_schema.tables t on
t.Table_name = so.Name
CROSS APPLY (
SELECT QuoteName(Column_Name) + ', '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY ORDINAL_POSITION
FOR XML PATH('')
) j (list)
WHERE
xtype = 'U'
AND name NOT IN ('dtproperties')
-- AND so.name = 'ASPStateTempSessions'
;
..
For use in Management Studio:
One detractor to the sql code above is if you test it using SSMS, long statements aren't easy to read. So, as per this helpful post, here's another version that's somewhat modified to be easier on the eyes after clicking the link of a cell in the grid. The results are more readily identifiable as nicely formatted CREATE TABLE statements for each table in the db.
-- settings
DECLARE #CRLF NCHAR(2)
SET #CRLF = Nchar(13) + NChar(10)
DECLARE #PLACEHOLDER NCHAR(3)
SET #PLACEHOLDER = '{:}'
-- the main query
SELECT
t.TABLE_CATALOG,
t.TABLE_SCHEMA,
t.TABLE_NAME,
CAST(
REPLACE(
'create table ' + QuoteName(t.TABLE_SCHEMA) + '.' + QuoteName(so.name) + ' (' + #CRLF
+ LEFT(o.List, Len(o.List) - (LEN(#PLACEHOLDER)+2)) + #CRLF + ');' + #CRLF
+ CASE WHEN tc.Constraint_Name IS NULL THEN ''
ELSE
'ALTER TABLE ' + QuoteName(t.TABLE_SCHEMA) + '.' + QuoteName(so.Name)
+ ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY (' + LEFT(j.List, Len(j.List) - 1) + ');' + #CRLF
END,
#PLACEHOLDER,
#CRLF
)
AS XML) as 'SQL_CREATE_TABLE'
FROM sysobjects so
CROSS APPLY (
SELECT
' '
+ '['+column_name+'] '
+ data_type
+ case data_type
when 'sql_variant' then ''
when 'text' then ''
when 'ntext' then ''
when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
else
coalesce(
'('+ case when character_maximum_length = -1
then 'MAX'
else cast(character_maximum_length as varchar) end
+ ')','')
end
+ ' '
+ case when exists (
SELECT id
FROM syscolumns
WHERE
object_name(id) = so.name
and name = column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(so.name) as varchar) + ',' +
cast(ident_incr(so.name) as varchar) + ')'
else ''
end
+ ' '
+ (case when IS_NULLABLE = 'No' then 'NOT ' else '' end)
+ 'NULL '
+ case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT
ELSE ''
END
+ ', '
+ #PLACEHOLDER -- note, can't have a field name or we'll end up with XML
FROM information_schema.columns where table_name = so.name
ORDER BY ordinal_position
FOR XML PATH('')
) o (list)
LEFT JOIN information_schema.table_constraints tc on
tc.Table_name = so.Name
AND tc.Constraint_Type = 'PRIMARY KEY'
LEFT JOIN information_schema.tables t on
t.Table_name = so.Name
CROSS APPLY (
SELECT QUOTENAME(Column_Name) + ', '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY ORDINAL_POSITION
FOR XML PATH('')
) j (list)
WHERE
xtype = 'U'
AND name NOT IN ('dtproperties')
-- AND so.name = 'ASPStateTempSessions'
;
Not to belabor the point, but here's the functionally equivalent example outputs for comparison:
-- 1 (scripting version)
create table [dbo].[ASPStateTempApplications] ( [AppId] int NOT NULL , [AppName] char(280) NOT NULL ); ALTER TABLE [dbo].[ASPStateTempApplications] ADD CONSTRAINT PK__ASPState__8E2CF7F908EA5793 PRIMARY KEY ([AppId]);
-- 2 (SSMS version)
create table [dbo].[ASPStateTempSessions] (
[SessionId] nvarchar(88) NOT NULL ,
[Created] datetime NOT NULL DEFAULT (getutcdate()),
[Expires] datetime NOT NULL ,
[LockDate] datetime NOT NULL ,
[LockDateLocal] datetime NOT NULL ,
[LockCookie] int NOT NULL ,
[Timeout] int NOT NULL ,
[Locked] bit NOT NULL ,
[SessionItemShort] varbinary(7000) NULL ,
[SessionItemLong] image(2147483647) NULL ,
[Flags] int NOT NULL DEFAULT ((0))
);
ALTER TABLE [dbo].[ASPStateTempSessions] ADD CONSTRAINT PK__ASPState__C9F4929003317E3D PRIMARY KEY ([SessionId]);
..
Detracting factors:
It should be noted that I remain relatively unhappy with this due to the lack of support for indeces other than a primary key. It remains suitable for use as a mechanism for simple data export or replication.
If the application you are generating the scripts from is a .NET application, you may want to look into using SMO (Sql Management Objects). Reference this SQL Team link on how to use SMO to script objects.
One more variant with foreign keys support and in one statement:
SELECT
obj.name
,'CREATE TABLE [' + obj.name + '] (' + LEFT(cols.list, LEN(cols.list) - 1 ) + ')'
+ ISNULL(' ' + refs.list, '')
FROM sysobjects obj
CROSS APPLY (
SELECT
CHAR(10)
+ ' [' + column_name + '] '
+ data_type
+ CASE data_type
WHEN 'sql_variant' THEN ''
WHEN 'text' THEN ''
WHEN 'ntext' THEN ''
WHEN 'xml' THEN ''
WHEN 'decimal' THEN '(' + CAST(numeric_precision as VARCHAR) + ', ' + CAST(numeric_scale as VARCHAR) + ')'
ELSE COALESCE('(' + CASE WHEN character_maximum_length = -1 THEN 'MAX' ELSE CAST(character_maximum_length as VARCHAR) END + ')', '')
END
+ ' '
+ case when exists ( -- Identity skip
select id from syscolumns
where object_name(id) = obj.name
and name = column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(obj.name) as varchar) + ',' +
cast(ident_incr(obj.name) as varchar) + ')'
else ''
end + ' '
+ CASE WHEN IS_NULLABLE = 'No' THEN 'NOT ' ELSE '' END
+ 'NULL'
+ CASE WHEN information_schema.columns.column_default IS NOT NULL THEN ' DEFAULT ' + information_schema.columns.column_default ELSE '' END
+ ','
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE table_name = obj.name
ORDER BY ordinal_position
FOR XML PATH('')
) cols (list)
CROSS APPLY(
SELECT
CHAR(10) + 'ALTER TABLE ' + obj.name + '_noident_temp ADD ' + LEFT(alt, LEN(alt)-1)
FROM(
SELECT
CHAR(10)
+ ' CONSTRAINT ' + tc.constraint_name
+ ' ' + tc.constraint_type + ' (' + LEFT(c.list, LEN(c.list)-1) + ')'
+ COALESCE(CHAR(10) + r.list, ', ')
FROM
information_schema.table_constraints tc
CROSS APPLY(
SELECT
'[' + kcu.column_name + '], '
FROM
information_schema.key_column_usage kcu
WHERE
kcu.constraint_name = tc.constraint_name
ORDER BY
kcu.ordinal_position
FOR XML PATH('')
) c (list)
OUTER APPLY(
-- // http://stackoverflow.com/questions/3907879/sql-server-howto-get-foreign-key-reference-from-information-schema
SELECT
' REFERENCES [' + kcu1.constraint_schema + '].' + '[' + kcu2.table_name + ']' + '(' + kcu2.column_name + '), '
FROM information_schema.referential_constraints as rc
JOIN information_schema.key_column_usage as kcu1 ON (kcu1.constraint_catalog = rc.constraint_catalog AND kcu1.constraint_schema = rc.constraint_schema AND kcu1.constraint_name = rc.constraint_name)
JOIN information_schema.key_column_usage as kcu2 ON (kcu2.constraint_catalog = rc.unique_constraint_catalog AND kcu2.constraint_schema = rc.unique_constraint_schema AND kcu2.constraint_name = rc.unique_constraint_name AND kcu2.ordinal_position = KCU1.ordinal_position)
WHERE
kcu1.constraint_catalog = tc.constraint_catalog AND kcu1.constraint_schema = tc.constraint_schema AND kcu1.constraint_name = tc.constraint_name
) r (list)
WHERE tc.table_name = obj.name
FOR XML PATH('')
) a (alt)
) refs (list)
WHERE
xtype = 'U'
AND name NOT IN ('dtproperties')
AND obj.name = 'your_table_name'
You could try in is sqlfiddle: http://sqlfiddle.com/#!6/e3b66/3/0
I modified the accepted answer and now it can get the command including primary key and foreign key in a certain schema.
declare #table varchar(100)
declare #schema varchar(100)
set #table = 'Persons' -- set table name here
set #schema = 'OT' -- set SCHEMA name here
declare #sql table(s varchar(1000), id int identity)
-- create statement
insert into #sql(s) values ('create table ' + #table + ' (')
-- column list
insert into #sql(s)
select
' '+column_name+' ' +
data_type + coalesce('('+cast(character_maximum_length as varchar)+')','') + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=#table
and name=column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(#table) as varchar) + ',' +
cast(ident_incr(#table) as varchar) + ')'
else ''
end + ' ' +
( case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
coalesce('DEFAULT '+COLUMN_DEFAULT,'') + ','
from information_schema.columns where table_name = #table and table_schema = #schema
order by ordinal_position
-- primary key
declare #pkname varchar(100)
select #pkname = constraint_name from information_schema.table_constraints
where table_name = #table and constraint_type='PRIMARY KEY'
if ( #pkname is not null ) begin
insert into #sql(s) values(' PRIMARY KEY (')
insert into #sql(s)
select ' '+COLUMN_NAME+',' from information_schema.key_column_usage
where constraint_name = #pkname
order by ordinal_position
-- remove trailing comma
update #sql set s=left(s,len(s)-1) where id=##identity
insert into #sql(s) values (' )')
end
else begin
-- remove trailing comma
update #sql set s=left(s,len(s)-1) where id=##identity
end
-- foreign key
declare #fkname varchar(100)
select #fkname = constraint_name from information_schema.table_constraints
where table_name = #table and constraint_type='FOREIGN KEY'
if ( #fkname is not null ) begin
insert into #sql(s) values(',')
insert into #sql(s) values(' FOREIGN KEY (')
insert into #sql(s)
select ' '+COLUMN_NAME+',' from information_schema.key_column_usage
where constraint_name = #fkname
order by ordinal_position
-- remove trailing comma
update #sql set s=left(s,len(s)-1) where id=##identity
insert into #sql(s) values (' ) REFERENCES ')
insert into #sql(s)
SELECT
OBJECT_NAME(fk.referenced_object_id)
FROM
sys.foreign_keys fk
INNER JOIN
sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN
sys.columns c1 ON fkc.parent_column_id = c1.column_id AND fkc.parent_object_id = c1.object_id
INNER JOIN
sys.columns c2 ON fkc.referenced_column_id = c2.column_id AND fkc.referenced_object_id = c2.object_id
where fk.name = #fkname
insert into #sql(s)
SELECT
'('+c2.name+')'
FROM
sys.foreign_keys fk
INNER JOIN
sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN
sys.columns c1 ON fkc.parent_column_id = c1.column_id AND fkc.parent_object_id = c1.object_id
INNER JOIN
sys.columns c2 ON fkc.referenced_column_id = c2.column_id AND fkc.referenced_object_id = c2.object_id
where fk.name = #fkname
end
-- closing bracket
insert into #sql(s) values( ')' )
-- result!
select s from #sql order by id
I'm going to improve the answer by supporting partitioned tables:
find partition scheme and partition key using below scritps:
declare #partition_scheme varchar(100) = (
select distinct ps.Name AS PartitionScheme
from sys.indexes i
join sys.partitions p ON i.object_id=p.object_id AND i.index_id=p.index_id
join sys.partition_schemes ps on ps.data_space_id = i.data_space_id
where i.object_id = object_id('your table name')
)
print #partition_scheme
declare #partition_column varchar(100) = (
select c.name
from sys.tables t
join sys.indexes i
on(i.object_id = t.object_id
and i.index_id < 2)
join sys.index_columns ic
on(ic.partition_ordinal > 0
and ic.index_id = i.index_id and ic.object_id = t.object_id)
join sys.columns c
on(c.object_id = ic.object_id
and c.column_id = ic.column_id)
where t.object_id = object_id('your table name')
)
print #partition_column
then change the generation query by adding below line at the right place:
+ IIF(#partition_scheme is null, '', 'ON [' + #partition_scheme + ']([' + #partition_column + '])')
Credit due to #Blorgbeard for sharing his script. I'll certainly bookmark it in case I need it.
Yes, you can "right click" on the table and script the CREATE TABLE script, but:
The a script will contain loads of cruft (interested in the extended properties anyone?)
If you have 200+ tables in your schema, it's going to take you half a day to script the lot by hand.
With this script converted into a stored procedure, and combined with a wrapper script you would have a nice automated way to dump your table design into source control etc.
The rest of your DB code (SP's, FK indexes, Triggers etc) would be under source control anyway ;)
Something I've noticed - in the INFORMATION_SCHEMA.COLUMNS view, CHARACTER_MAXIMUM_LENGTH gives a size of 2147483647 (2^31-1) for field types such as image and text. ntext is 2^30-1 (being double-byte unicode and all).
This size is included in the output from this query, but it is invalid for these data types in a CREATE statement (they should not have a maximum size value at all). So unless the results from this are manually corrected, the CREATE script won't work given these data types.
I imagine it's possible to fix the script to account for this, but that's beyond my SQL capabilities.
-- or you could create a stored procedure ... first with Id creation
USE [db]
GO
/****** Object: StoredProcedure [dbo].[procUtils_InsertGeneratorWithId] Script Date: 06/13/2009 22:18:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create PROC [dbo].[procUtils_InsertGeneratorWithId]
(
#domain_user varchar(50),
#tableName varchar(100)
)
as
--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR
SELECT column_name,data_type FROM information_schema.columns WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(3000) --for storing the first half of INSERT statement
DECLARE #stringData nvarchar(3000) --for storing the data (VALUES) related statement
DECLARE #dataType nvarchar(1000) --data types returned for respective columns
DECLARE #IDENTITY_STRING nvarchar ( 100 )
SET #IDENTITY_STRING = ' '
select #IDENTITY_STRING
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
begin
print 'Table '+#tableName+' not found, processing skipped.'
close curscol
deallocate curscol
return
END
WHILE ##FETCH_STATUS=0
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
--SET #stringData=#stringData+'''''''''+isnull('+#colName+','''')+'''''',''+'
SET #stringData=#stringData+''''+'''+isnull('''''+'''''+'+#colName+'+'''''+''''',''NULL'')+'',''+'
END
ELSE
if #dataType in ('text','ntext') --if the datatype is text or something else
BEGIN
SET #stringData=#stringData+'''''''''+isnull(cast('+#colName+' as varchar(2000)),'''')+'''''',''+'
END
ELSE
IF #dataType = 'money' --because money doesn't get converted from varchar implicitly
BEGIN
SET #stringData=#stringData+'''convert(money,''''''+isnull(cast('+#colName+' as varchar(200)),''0.0000'')+''''''),''+'
END
ELSE
IF #dataType='datetime'
BEGIN
--SET #stringData=#stringData+'''convert(datetime,''''''+isnull(cast('+#colName+' as varchar(200)),''0'')+''''''),''+'
--SELECT 'INSERT Authorizations(StatusDate) VALUES('+'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations
--SET #stringData=#stringData+'''convert(money,''''''+isnull(cast('+#colName+' as varchar(200)),''0.0000'')+''''''),''+'
SET #stringData=#stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+',121)+'''''+''''',''NULL'')+'',121),''+'
-- 'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations
END
ELSE
IF #dataType='image'
BEGIN
SET #stringData=#stringData+'''''''''+isnull(cast(convert(varbinary,'+#colName+') as varchar(6)),''0'')+'''''',''+'
END
ELSE --presuming the data type is int,bit,numeric,decimal
BEGIN
--SET #stringData=#stringData+'''''''''+isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
--SET #stringData=#stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+',121)+'''''+''''',''NULL'')+'',121),''+'
SET #stringData=#stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+')+'''''+''''',''NULL'')+'',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #colName,#dataType
END
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ') VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')'' FROM '+#tableName
exec sp_executesql #query
--select #query
CLOSE cursCol
DEALLOCATE cursCol
/*
USAGE
*/
GO
-- and second without iD INSERTION
USE [db]
GO
/****** Object: StoredProcedure [dbo].[procUtils_InsertGenerator] Script Date: 06/13/2009 22:20:52 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[procUtils_InsertGenerator]
(
#domain_user varchar(50),
#tableName varchar(100)
)
as
--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR
-- SELECT column_name,data_type FROM information_schema.columns WHERE table_name = #tableName
/* NEW
SELECT c.name , sc.data_type FROM sys.extended_properties AS ep
INNER JOIN sys.tables AS t ON ep.major_id = t.object_id
INNER JOIN sys.columns AS c ON ep.major_id = c.object_id AND ep.minor_id
= c.column_id
INNER JOIN INFORMATION_SCHEMA.COLUMNS sc ON t.name = sc.table_name and
c.name = sc.column_name
WHERE t.name = #tableName and c.is_identity=0
*/
select object_name(c.object_id) "TABLE_NAME", c.name "COLUMN_NAME", s.name "DATA_TYPE"
from sys.columns c
join sys.systypes s on (s.xtype = c.system_type_id)
where object_name(c.object_id) in (select name from sys.tables where name not like 'sysdiagrams')
AND object_name(c.object_id) in (select name from sys.tables where [name]=#tableName ) and c.is_identity=0 and s.name not like 'sysname'
OPEN cursCol
DECLARE #string nvarchar(3000) --for storing the first half of INSERT statement
DECLARE #stringData nvarchar(3000) --for storing the data (VALUES) related statement
DECLARE #dataType nvarchar(1000) --data types returned for respective columns
DECLARE #IDENTITY_STRING nvarchar ( 100 )
SET #IDENTITY_STRING = ' '
select #IDENTITY_STRING
SET #string='INSERT '+#tableName+'('
SET #stringData=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #tableName , #colName,#dataType
IF ##fetch_status<>0
begin
print 'Table '+#tableName+' not found, processing skipped.'
close curscol
deallocate curscol
return
END
WHILE ##FETCH_STATUS=0
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
--SET #stringData=#stringData+'''''''''+isnull('+#colName+','''')+'''''',''+'
SET #stringData=#stringData+''''+'''+isnull('''''+'''''+'+#colName+'+'''''+''''',''NULL'')+'',''+'
END
ELSE
if #dataType in ('text','ntext') --if the datatype is text or something else
BEGIN
SET #stringData=#stringData+'''''''''+isnull(cast('+#colName+' as varchar(2000)),'''')+'''''',''+'
END
ELSE
IF #dataType = 'money' --because money doesn't get converted from varchar implicitly
BEGIN
SET #stringData=#stringData+'''convert(money,''''''+isnull(cast('+#colName+' as varchar(200)),''0.0000'')+''''''),''+'
END
ELSE
IF #dataType='datetime'
BEGIN
--SET #stringData=#stringData+'''convert(datetime,''''''+isnull(cast('+#colName+' as varchar(200)),''0'')+''''''),''+'
--SELECT 'INSERT Authorizations(StatusDate) VALUES('+'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations
--SET #stringData=#stringData+'''convert(money,''''''+isnull(cast('+#colName+' as varchar(200)),''0.0000'')+''''''),''+'
SET #stringData=#stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+',121)+'''''+''''',''NULL'')+'',121),''+'
-- 'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations
END
ELSE
IF #dataType='image'
BEGIN
SET #stringData=#stringData+'''''''''+isnull(cast(convert(varbinary,'+#colName+') as varchar(6)),''0'')+'''''',''+'
END
ELSE --presuming the data type is int,bit,numeric,decimal
BEGIN
--SET #stringData=#stringData+'''''''''+isnull(cast('+#colName+' as varchar(200)),''0'')+'''''',''+'
--SET #stringData=#stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+',121)+'''''+''''',''NULL'')+'',121),''+'
SET #stringData=#stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+')+'''''+''''',''NULL'')+'',''+'
END
SET #string=#string+#colName+','
FETCH NEXT FROM cursCol INTO #tableName , #colName,#dataType
END
DECLARE #Query nvarchar(4000)
SET #query ='SELECT '''+substring(#string,0,len(#string)) + ') VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')'' FROM '+#tableName
exec sp_executesql #query
--select #query
CLOSE cursCol
DEALLOCATE cursCol
/*
use poc
go
DECLARE #RC int
DECLARE #domain_user varchar(50)
DECLARE #tableName varchar(100)
-- TODO: Set parameter values here.
set #domain_user='yorgeorg'
set #tableName = 'tbGui_WizardTabButtonAreas'
EXECUTE #RC = [POC].[dbo].[procUtils_InsertGenerator]
#domain_user
,#tableName
*/
GO
Show create table in classic asp (handles constraints, primary keys, copying the table structure and/or data ...)
Sql server Show create table
Mysql-style "Show create table" and "show create database" commands from Microsoft sql server.
The script is written is Microsoft asp-language and is quite easy to port to another language.*
I include definitions for computed columns
select 'CREATE TABLE [' + so.name + '] (' + o.list + ')' + CASE WHEN tc.Constraint_Name IS NULL THEN '' ELSE 'ALTER TABLE ' + so.Name + ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ')' END, name
from sysobjects so
cross apply
(SELECT
case when comps.definition is not null then ' ['+column_name+'] AS ' + comps.definition
else
' ['+column_name+'] ' + data_type +
case
when data_type like '%text' or data_type in ('image', 'sql_variant' ,'xml')
then ''
when data_type in ('float')
then '(' + cast(coalesce(numeric_precision, 18) as varchar(11)) + ')'
when data_type in ('datetime2', 'datetimeoffset', 'time')
then '(' + cast(coalesce(datetime_precision, 7) as varchar(11)) + ')'
when data_type in ('decimal', 'numeric')
then '(' + cast(coalesce(numeric_precision, 18) as varchar(11)) + ',' + cast(coalesce(numeric_scale, 0) as varchar(11)) + ')'
when (data_type like '%binary' or data_type like '%char') and character_maximum_length = -1
then '(max)'
when character_maximum_length is not null
then '(' + cast(character_maximum_length as varchar(11)) + ')'
else ''
end + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=so.name
and name=column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(so.name) as varchar) + ',' +
cast(ident_incr(so.name) as varchar) + ')'
else ''
end + ' ' +
(case when information_schema.columns.IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT ELSE '' END
end + ', '
from information_schema.columns
left join sys.computed_columns comps
on OBJECT_ID(information_schema.columns.TABLE_NAME)=comps.object_id and information_schema.columns.COLUMN_NAME=comps.name
where table_name = so.name
order by ordinal_position
FOR XML PATH('')) o (list)
left join
information_schema.table_constraints tc
on tc.Table_name = so.Name
AND tc.Constraint_Type = 'PRIMARY KEY'
cross apply
(select '[' + Column_Name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY
ORDINAL_POSITION
FOR XML PATH('')) j (list)
where xtype = 'U'
AND name NOT IN ('dtproperties')
I realise that it's been a very long time but thought I'd add anyway. If you just want the table, and not the create table statement you could use
select into x from db.schema.y where 1=0
to copy the table to a new DB
A query based on Hubbitus answer.
includes schema names
fixes foreign keys with more than one field
includes CASCADE UPDATE & DELETE
includes a conditioned DROP TABLE
SELECT
Schema_Name = SCHEMA_NAME(obj.uid)
, Table_Name = name
, Drop_Table = 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ''' + SCHEMA_NAME(obj.uid) + ''' AND TABLE_NAME = ''' + obj.name + '''))
DROP TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] '
, Create_Table ='
CREATE TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] (' + LEFT(cols.list, LEN(cols.list) - 1 ) + ')' + ISNULL(' ' + refs.list, '')
FROM sysobjects obj
CROSS APPLY (
SELECT
CHAR(10)
+ ' [' + column_name + '] '
+ data_type
+ CASE data_type
WHEN 'sql_variant' THEN ''
WHEN 'text' THEN ''
WHEN 'ntext' THEN ''
WHEN 'xml' THEN ''
WHEN 'decimal' THEN '(' + CAST(numeric_precision as VARCHAR) + ', ' + CAST(numeric_scale as VARCHAR) + ')'
ELSE COALESCE('(' + CASE WHEN character_maximum_length = -1 THEN 'MAX' ELSE CAST(character_maximum_length as VARCHAR) END + ')', '')
END
+ ' '
+ case when exists ( -- Identity skip
select id from syscolumns
where id = obj.id
and name = column_name
and columnproperty(id, name, 'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(obj.name) as varchar) + ',' +
cast(ident_incr(obj.name) as varchar) + ')'
else ''
end + ' '
+ CASE WHEN IS_NULLABLE = 'No' THEN 'NOT ' ELSE '' END
+ 'NULL'
+ CASE WHEN IC.column_default IS NOT NULL THEN ' DEFAULT ' + IC.column_default ELSE '' END
+ ','
FROM INFORMATION_SCHEMA.COLUMNS IC
WHERE IC.table_name = obj.name
AND IC.TABLE_SCHEMA = SCHEMA_NAME(obj.uid)
ORDER BY ordinal_position
FOR XML PATH('')
) cols (list)
CROSS APPLY(
SELECT
CHAR(10) + 'ALTER TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] ADD ' + LEFT(alt, LEN(alt)-1)
FROM(
SELECT
CHAR(10)
+ ' CONSTRAINT ' + tc.constraint_name
+ ' ' + tc.constraint_type + ' (' + LEFT(c.list, LEN(c.list)-1) + ')'
+ COALESCE(CHAR(10) + r.list, ', ')
FROM information_schema.table_constraints tc
CROSS APPLY(
SELECT '[' + kcu.column_name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.constraint_name = tc.constraint_name
ORDER BY kcu.ordinal_position
FOR XML PATH('')
) c (list)
OUTER APPLY(
-- // http://stackoverflow.com/questions/3907879/sql-server-howto-get-foreign-key-reference-from-information-schema
SELECT LEFT(f.list, LEN(f.list)-1) + ')' + IIF(rc.DELETE_RULE = 'NO ACTION', '', ' ON DELETE ' + rc.DELETE_RULE) + IIF(rc.UPDATE_RULE = 'NO ACTION', '', ' ON UPDATE ' + rc.UPDATE_RULE) + ', '
FROM information_schema.referential_constraints rc
CROSS APPLY(
SELECT IIF(kcu.ordinal_position = 1, ' REFERENCES [' + kcu.table_schema + '].[' + kcu.table_name + '] (', '')
+ '[' + kcu.column_name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.constraint_catalog = rc.unique_constraint_catalog AND kcu.constraint_schema = rc.unique_constraint_schema AND kcu.constraint_name = rc.unique_constraint_name
ORDER BY kcu.ordinal_position
FOR XML PATH('')
) f (list)
WHERE rc.constraint_catalog = tc.constraint_catalog
AND rc.constraint_schema = tc.constraint_schema
AND rc.constraint_name = tc.constraint_name
) r (list)
WHERE tc.table_name = obj.name
FOR XML PATH('')
) a (alt)
) refs (list)
WHERE xtype = 'U'
To combine drop table (if exists) with create use like this:
SELECT Drop_Table + CHAR(10) + Create_Table FROM SysCreateTables
If you are using management studio and have the query analyzer window open you can drag the table name to the query analyzer window and ... bingo! you get the table script.
I've not tried this in SQL2008

Resources