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
Related
I want to change a specific value at unknown table or column. I reached to the code helped me to search it. I found that at some tables, it's the primary column.
I must do this job because I have a lot of values that need to be changed.
I tried to do the code but I got lot of errors:
Invalid column name 'TableNameA'.
Invalid column name 'ColumnNameA'.
Hope get help as I'm still new for SQL.
What should I do?
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '4523'
Declare #NewValueInt int = 4195403
Declare #NewValueVarChar nvarchar(20) = '4194523'
/* use LIKE syntax */
SET #FullRowResult = 1
SET #FullRowResultRows = 3
SET #SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET #SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET #SearchStrInXML = 0 /* Searching XML data may be slow */
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256) = '',#ColumnName nvarchar(128),#ColumnType nvarchar(20), #QuotedSearchStrColumnValue nvarchar(110), #QuotedSearchStrColumnName nvarchar(110)
SET #QuotedSearchStrColumnValue = QUOTENAME(#SearchStrColumnValue,'''')
DECLARE #ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))
WHILE #TableName IS NOT NULL
BEGIN
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE COALESCE(#SearchStrTableName,TABLE_NAME)
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
IF #TableName IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''' + #TableName + ''', 1)
AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE #SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN #SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + #SearchStrColumnName + '''' END + ',COLUMN_NAME)'
INSERT INTO #ColumnNameTable
EXEC (#sql)
WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM #ColumnNameTable)
BEGIN
PRINT #ColumnName
SELECT TOP 1 #ColumnName = COLUMN_NAME,#ColumnType = DATA_TYPE FROM #ColumnNameTable
SET #sql = 'SELECT ''' + #TableName + ''',''' + #ColumnName + ''',' + CASE #ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + #ColumnName + ' AS nvarchar(MAX)), 4096),'''
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + '),'''
ELSE 'LEFT(' + #ColumnName + ', 4096),''' END + #ColumnType + '''
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
INSERT INTO #Results
EXEC(#sql)
IF ##ROWCOUNT > 0 IF #FullRowResult = 1
BEGIN
SET #sql = 'SELECT TOP ' + CAST(#FullRowResultRows AS VARCHAR(3)) + ' ''' + #TableName + ''' AS [TableFound],''' + #ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
' FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
EXEC(#sql)
DECLARE #sqlU VARCHAR(MAX)
Declare #sqlN VARCHAR(MAX)
SET #sqlU = N'UPDATE ' + quotename(#SearchStrTableName) + ' SET ' +quotename(#SearchStrColumnName)+ ' = ''' +#NewValueVarChar+ ''' WHERE ' +quotename(#SearchStrColumnName)+ ' = ''' + #SearchStrColumnValue + '''';
EXEC (#sqlU)
SET #sqlN = N'Update ' + quotename(#SearchStrTableName) + ' SET '+ quotename(#SearchStrColumnName) +'=''' +#NewValueVarChar+ '''where'+ quotename(#SearchStrColumnName) + '='+ #SearchStrColumnValue
EXEC (#sqlN)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
IF OBJECT_ID('tempdb..#Abd_tmptbl') IS NOT NULL DROP TABLE #Abd_tmptbl
CREATE TABLE #Abd_tmptbl (TableNameA nvarchar(128), ColumnNameA nvarchar(128), ColumnValueA nvarchar(max),ColumnTypeA nvarchar(20), Count int)
INSERT INTO #Abd_tmptbl
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
DECLARE #Tableee VARCHAR(20), #Columnee varchar(20), #Constraint varchar(20)
DECLARE #items TABLE(tabl int, clmn int)
Create Table #PK_tbl (PK_Col varchar (10))
WHILE EXISTS (select TOP 1 TableNameA FROM #Abd_tmptbl)
BEGIN
SELECT TOP 1 #Tableee = TableNameA, #Columnee = ColumnNameA
------------ GET All PKs of the Table ---------------------
DECLARE #PK_sql varchar(max) = N'INSERT INTO #PK_tbl(PK_Col)
(SELECT Col.Column_Name from INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab, INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE Col.Constraint_Name = Tab.Constraint_Name AND Col.Table_Name = Tab.Table_Name AND Constraint_Type = "PRIMARY KEY" AND Col.Table_Name = ' + #Tableee +')'
EXEC (#PK_sql)
------------------------------------------------------------
------------ GET CONTRAINT Name ----------------------------
SET #Constraint = N'SELECT name FROM sys.key_constraints WHERE type = "PK" AND OBJECT_NAME(parent_object_id) = ' + #Columnee
------------------------------------------------------------
------------ RELEASE Table From CONSTRAINTS ----------------
DECLARE #REL_tbl VARCHAR(max) = N'ALTER TABLE' + #Tableee +'DROP CONSTRAINT'+ #Constraint
EXEC (#REL_tbl)
------------------------------------------------------------
DECLARE #Update_tbl VARCHAR(max) = N'UPDATE '+ #Tableee + 'SET ' + #Columnee + '=' + #NewValueInt+ ' WHERE' + #Columnee + '=' + #SearchStrColumnValue
EXEC (#Update_tbl)
DECLARE #Sealing_tbl VARCHAR(max) = N'ALTER TABLE' + #Tableee + 'ADD CONSTRAINT' + #Constraint + 'PRIMARY KEY CLUSTERED (SELECT * FROM #PK_tbl)'
EXEC (#Update_tbl)
END
i have searched this one out for a while, but just don't know if there is a "silver bullet" solution to what I'm looking to do. I have a table in my DB (for the sake of this discussion the actual columns are irrelevant). I want to be able to look at 2 rows from the same table and get a list of columns that are different between the 2.
I know I could write a whole bunch of TSQL to make this happen for a specific table, but I was hoping there was a built in function in SQL Server (I'm running 2008 R2) that could do this.
I know there are simple functions like CHECKSUM that will tell me if 2 rows are different, but I need the specifics of which columns are different.
Preferably I would like to make it into a UDF and pass the table name, and primary keys of the 2 rows I want compared.
Any Thoughts or Suggestions?
--EDIT-- Here is the solution I came up with:
Well, It is certainly not the most elegant solution...but it will work in a pinch.
CREATE PROCEDURE sp_Compare_Table_Rows
(
#TablePK varchar(1000), -- The Name of the Primary Key in that Table
#TableName varchar(1000), -- The Name of the Table
#PK1 int, -- The ID of the 1st table
#PK2 int -- The ID of the 2nd table
)
AS
DECLARE #Holder table
(
Column_Name varchar(250),
Different bit
)
INSERT INTO #Holder(Column_Name,Different)
select
COLUMN_NAME,0
from
LPS_DEV.INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
and ORDINAL_POSITION >1
DECLARE #LoopedColumnName varchar(250)
DECLARE #DynamicQuery nvarchar(max)
DECLARE #ORD1 int
DECLARE #ORD2 int
SET #DynamicQuery = ''
SET #LoopedColumnName = ''
SET #ORD1 = 0
SET #ORD2 = 0
DECLARE MYCUR CURSOR FOR SELECT Column_Name FROM #Holder
OPEN MYCUR
FETCH NEXT FROM MYCUR INTO #LoopedColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #DynamicQuery = 'SELECT #Outer= CHECKSUM(' + #LoopedColumnName + ') FROM ' + #TableName + ' WHERE ' + #TablePK + ' = ' + CONVERT(varchar(100),#PK1)
exec sp_executesql #DynamicQuery, N'#Outer int output',#ORD1 out
SET #DynamicQuery = 'SELECT #Outer= CHECKSUM(' + #LoopedColumnName + ') FROM ' + #TableName + ' WHERE ' + #TablePK + ' = ' + CONVERT(varchar(100),#PK2)
exec sp_executesql #DynamicQuery, N'#Outer int output',#ORD2 out
IF #ORD1 <> #ORD2
BEGIN
UPDATE #Holder SET Different = 1 WHERE Column_Name = #LoopedColumnName
END
FETCH NEXT FROM MYCUR INTO #LoopedColumnName
END
CLOSE MYCUR
DEALLOCATE MYCUR
select * from #Holder
John, you can use something like this. This will display the column names -
Set the #tablename and #whereclause.
declare #tablename varchar(1000),
#cols varchar(max),
#sqlstmt nvarchar(max),
#whereclause nvarchar(max);
set #tablename = 'sometable';
set #whereclause = ' where
a.col1 = ''SOMEOTHERVALUE'' and a.datecol2 = ''19910101'' and
b.col2 = ''SOMEVALUE'' and b.datecol2 = ''19910101''
'
select #cols = stuff((
select ', case when a.' + c.name + ' = b.' + c.name
+ ' then '''' else ''' + c.name + ''' end'
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
for xml path ('')), 1, 1, '')
set #sqlstmt = 'select ' + #cols + ' from ' + #tablename
+ ' a, ' + #tablename + ' b ' + #whereclause
exec sp_executesql #sqlstmt
I did some enhancements on Sriram answer, here is the new script:
declare #tablename nvarchar(MAX),
#cols varchar(max) = '',
#sqlstmt nvarchar(max) = 'DECLARE #T AS TABLE (ColumnName NVARCHAR(MAX), Value NVARCHAR(MAX), Value2 NVARCHAR(MAX))',
#whereclause nvarchar(max) = '';
set #tablename = 'TABLE_NAME';
set #whereclause = ' where a.FIRST_ROW_ID = ''NUMBER'' and b.SECOND_ROW_ID = ''NUMBER'''
select #cols = (
select ' INSERT INTO #T SELECT ''' + c.name + ''', cast(a.' + c.name + ' as nvarchar(max)), cast(b.' + c.name + ' as nvarchar(max)) from ' + #tablename + ' a, ' + #tablename + ' b ' + #whereclause + ' AND cast(a.' + c.name + ' as nvarchar(max)) != cast(b.' + c.name + ' as nvarchar(max))'
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
for xml path (''))
set #sqlstmt += #cols + ' SELECT * FROM #T'
exec sp_executesql #sqlstmt
You need to replace 'TABLE_NAME' with your table and change the where clause variable.
The result will be like this:
ColumnName | Value | Value2
----------------------------
Id | 1 | 2
Name | Name 1 | Name 2
I have done further enhancement to Sriram Chitturi and Mohamed Noor's answer and also handled datetime comparison
ALTER PROC [dbo].[IdentifyNotMatchingColumnDataBetween2Rows] (
#table_name VARCHAR(300) = 'TableName'
,#excluded_columns VARCHAR(300) = 'Id,UpdateTimeStamp,InsertTimeStamp,IsDuplicate,NotMatchingColumns'
,#compare_row_id_1 INT = 1732340
,#compare_row_id_2 INT = 1736803
)
AS
/*
EXEC [dbo].[IdentifyNotMatchingColumnDataBetween2Rows]
*/
BEGIN
SET NOCOUNT ON;
DECLARE #cols VARCHAR(max) = ''
DECLARE #sqlstmt NVARCHAR(max) = 'DECLARE #T AS TABLE (ColumnName VARCHAR(300), Value NVARCHAR(MAX), Value2 NVARCHAR(MAX))'
DECLARE #where_clause NVARCHAR(max) = ' WHERE a.Id = ''' + CAST(#compare_row_id_1 as varchar(20)) + ''' and b.Id = ''' + CAST(#compare_row_id_2 as varchar(20)) + ''''
SELECT #cols = (
SELECT CASE
WHEN c.system_type_id = 106 --DECIMAL
OR c.system_type_id = 56 --INT
OR c.system_type_id = 48 --TINYINT
OR c.system_type_id = 52 --SMALLINT
OR c.system_type_id = 127 --BIGINT
OR c.system_type_id = 62 --FLOAT
OR c.system_type_id = 108 --NUMERIC
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', CAST(a.[' + c.name + '] AS NVARCHAR(MAX)), CAST(b.[' + c.name + '] AS NVARCHAR(MAX)) FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND CAST(ISNULL(a.[' + c.name + '],' + '-1' + ') AS NVARCHAR(MAX)) != CAST(ISNULL(b.[' + c.name + '],' + '-1' + ') AS NVARCHAR(MAX))'
WHEN c.system_type_id IN (61,42) -- DATETIME / DATETIME2
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', FORMAT(a.[' + c.name + '] ,''yyyyMMddHHmmssffff''), FORMAT(b.[' + c.name + '] ,''yyyyMMddHHmmssffff'') FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND FORMAT(ISNULL(a.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmssffff'') != FORMAT(ISNULL(b.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmssffff'')'
WHEN c.system_type_id = 58 --SMALLDATETIME
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', FORMAT(a.[' + c.name + '] ,''yyyyMMddHHmmss''), FORMAT(b.[' + c.name + '] ,''yyyyMMddHHmmss'') FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND FORMAT(ISNULL(a.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmss'') != FORMAT(ISNULL(b.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmss'')'
ELSE
' INSERT INTO #T SELECT ''[' + c.name + ']'', CAST(a.[' + c.name + '] AS NVARCHAR(MAX)), CAST(b.[' + c.name + '] AS NVARCHAR(MAX)) FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND CAST(ISNULL(a.[' + c.name + '],' + '''' + '''' + ') AS NVARCHAR(MAX)) != CAST(ISNULL(b.[' + c.name + '],' + '''' + '''' + ') AS NVARCHAR(MAX))'
END
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = #table_name
AND c.name NOT IN (
SELECT items
FROM dbo.Split(#excluded_columns, ',')
)
FOR XML path('')
)
SET #sqlstmt += #cols + ' SELECT * FROM #T';
--PRINT #sqlstmt;
EXEC sp_executesql #sqlstmt
END
To Execute
EXECUTE dbo.IdentifyNotMatchingColumnDataBetween2Rows 'TableName','Id,UpdateTimeStamp,InsertTimeStamp,Last Checked,IsDuplicate,NotMatchingColumns,',#row_id_1,#row_id_2;
I have a database with a lot of tables, and I want to rename the primary/foreign keys, indexes and default constraints according to the following rules :
Primary keys : PK_<table name>
Foreign keys : FK_<table_name>_<column name1>_column name2>...
Indexes : IX_<table_name>_<column name1>_column name2>...
Default Constraints : DF_<table_name>_<column name>
Check Constraints : CK_<table_name>_<column name>
Someone has already done a similar SQL script ?
To rename Primary Keys to simply PK_TableName:
CREATE PROCEDURE dbo.Rename_PrimaryKeys
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10) + 'EXEC sp_rename '''
+ REPLACE(name, '''', '''''') + ''', ''PK_'
+ REPLACE(OBJECT_NAME(parent_object_id), '''', '') + ''', ''OBJECT'';'
FROM sys.key_constraints
WHERE type = 'PK'
AND name <> 'PK_' + REPLACE(OBJECT_NAME(parent_object_id), '''', '')
AND OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
To rename FKs with the scheme FK_TableName_col_col_ReferencedName_col_col:
CREATE PROCEDURE dbo.Rename_ForeignKeys_WithColumns
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10)
+ 'EXEC sp_rename ''' + REPLACE(name, '''', '''''')
+ ''', ''FK_' + REPLACE(OBJECT_NAME(fk.parent_object_id), '''', '')
+ '_' + STUFF((SELECT '_' + REPLACE(c.name, '''', '')
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
+ '_' + REPLACE(OBJECT_NAME(fk.referenced_object_id), '''', '')
+ '_' + STUFF((SELECT '_' + REPLACE(c.name, '''', '')
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
+ ''', ''OBJECT'';'
FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
For foreign keys if you just want FK_TableName_ReferencedName then it's a lot simpler:
CREATE PROCEDURE dbo.Rename_ForeignKeys
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10) + 'EXEC sp_rename '''
+ REPLACE(name, '''', '''''') + ''', ''FK_'
+ REPLACE(OBJECT_NAME(parent_object_id), '''', '')
+ '_' + REPLACE(OBJECT_NAME(referenced_object_id), '''', '')
+ ''', ''OBJECT'';'
FROM sys.foreign_keys
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
For indexes, this will rename any indexes IX_TableName_Col1_Col2.... It will ignore primary keys (since they are dealt with separately above), will add UQ_ to unique indexes/constraints (so IX_UQ_TableName_Col1_Col2..., will treat unique constraints and unique indexes the same, and will ignore included columns. (Note that ignoring included columns could produce a naming conflict if you have redundant indexes that only differ by included columns.)
CREATE PROCEDURE dbo.Rename_Indexes
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10)
+ 'EXEC sp_rename ''' + REPLACE(i.name, '''', '''''')
+ ''', ''IX_' + CASE is_unique_constraint WHEN 1 THEN 'UQ_' ELSE '' END
+ REPLACE(OBJECT_NAME(i.[object_id]), '''', '')
+ '_' + STUFF((SELECT '_' + REPLACE(c.name, '''', '')
FROM sys.columns AS c
INNER JOIN sys.index_columns AS ic
ON ic.column_id = c.column_id
AND ic.[object_id] = c.[object_id]
WHERE ic.[object_id] = i.[object_id]
AND ic.index_id = i.index_id
AND is_included_column = 0
ORDER BY ic.index_column_id
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
+''', ''OBJECT'';'
FROM sys.indexes AS i
WHERE index_id > 0
AND is_primary_key = 0 -- dealt with separately
AND OBJECTPROPERTY(i.[object_id], 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
For default constraints:
CREATE PROCEDURE dbo.Rename_DefaultConstraints
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10)
+ 'EXEC sp_rename ''' + REPLACE(dc.name, '''', '''''')
+ ''', ''DF_' + REPLACE(OBJECT_NAME(dc.parent_object_id), '''','')
+ '_' + REPLACE(c.name, '''', '') + ''', ''OBJECT'';'
FROM sys.default_constraints AS dc
INNER JOIN sys.columns AS c
ON dc.parent_object_id = c.[object_id]
AND dc.parent_column_id = c.column_id
AND OBJECTPROPERTY(dc.parent_object_id, 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
And finally check constraints:
CREATE PROCEDURE dbo.Rename_CheckConstraints
#PrintOnly BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + CHAR(13) + CHAR(10)
+ 'EXEC sp_rename ''' + REPLACE(cc.name, '''', '''''')
+ ''', ''CK_' + REPLACE(OBJECT_NAME(cc.parent_object_id), '''','')
+ '_' + REPLACE(c.name, '''', '') + ''', ''OBJECT'';'
FROM sys.check_constraints AS cc
INNER JOIN sys.columns AS c
ON cc.parent_object_id = c.[object_id]
AND cc.parent_column_id = c.column_id
AND OBJECTPROPERTY(dc.parent_object_id, 'IsMsShipped') = 0;
PRINT #sql;
IF #PrintOnly = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
END
GO
Note that PRINT won't necessarily reveal the entire statement, depending on your settings for results in text and the size of the statement. But it should be good enough to eyeball that the scripts are doing the right job. I set them all to PrintOnly by default.
And to rename the foreign keys, you can use something like this (this is not yet doing exactly what you wanted - but close enough to get started on it):
DECLARE RenameFKCursor CURSOR FAST_FORWARD
FOR
SELECT
'dbo.sp_rename #objName = ''' + fk.Name + ''', #NewName = ''FK_' + t.Name + '_' + ref.Name + ''', #objtype = ''OBJECT'''
FROM
sys.foreign_keys fk
INNER JOIN
sys.tables t ON fk.parent_object_id = t.object_id
INNER JOIN
sys.tables ref ON fk.referenced_object_id = ref.object_id
WHERE
fk.is_system_named = 1
DECLARE #RenameFKStmt NVARCHAR(500)
OPEN RenameFKCursor
FETCH NEXT FROM RenameFKCursor INTO #RenameFKStmt
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
PRINT #RenameFKStmt
EXEC(#RenameFKStmt)
END
FETCH NEXT FROM RenameFKCursor INTO #RenameFKStmt
END
CLOSE RenameFKCursor
DEALLOCATE RenameFKCursor
GO
Basically, you iterate over all foreign keys defined in your database, and you rename them to some name that you decide on how to construct in the SELECT that is the basis of this cursor.
Then you run the cursor over all results, and execute the dbo.sp_rename stored procedure to rename your FK constraint to whatever you want them to be.
Using Aaron's approach of just basically building up one single huge SQL statement, you could even get away without having to use a cursor.
This would be the very similar code to rename the "system-named" default constraints to your own naming convention - it uses the same approach as above, a SELECT against the system catalog views, and then a cursor to iterate over all entries and build up and execute a SQL rename statement:
DECLARE DFCursor CURSOR FAST_FORWARD
FOR
SELECT
dc.Name,
t.Name,
c.Name
FROM
sys.default_constraints dc
INNER JOIN
sys.tables t ON dc.parent_object_id = t.object_id
INNER JOIN
sys.columns c ON dc.parent_column_id = c.column_id AND dc.parent_object_id = c.object_id
WHERE
is_system_named = 1
DECLARE #OldConstraintName sysname, #TableName sysname, #ColumnName sysname
OPEN DFCursor
FETCH NEXT FROM DFCursor INTO #OldConstraintName, #TableName, #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Stmt NVARCHAR(999)
SET #Stmt = 'dbo.sp_rename #objName = ''' + #OldConstraintName + ''', #NewName = ''DF_' + #TableName + '_' + #ColumnName + ''', #objtype = ''OBJECT'''
PRINT #Stmt
EXEC (#Stmt)
FETCH NEXT FROM DFCursor INTO #OldConstraintName, #TableName, #ColumnName
END
CLOSE DFCursor
DEALLOCATE DFCursor
Provided solutions will break if DB has similar tables in different schemas. Here's my modification of this solution, that i use.
CREATE PROCEDURE dbo._ImplementNamingStandard
#SELECT_Only BIT = 1,
#PrimaryKeys BIT = 1,
#ForeignKeys BIT = 1,
#Indexes BIT = 1,
#UniqueConstraints BIT = 1,
#DefaultConstraints BIT = 1,
#CheckConstraints BIT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX), #cr CHAR(2);
SELECT #sql = N'', #cr = CHAR(13) + CHAR(10);
DECLARE #TableLimit TINYINT, #ColumnLimit TINYINT;
SELECT #TableLimit = 24, #ColumnLimit = 24;
Primary Keys:
IF #PrimaryKeys = 1
BEGIN
SELECT #sql = #sql + #cr + #cr + N'/* ---- Primary Keys ---- */' + #cr;
SELECT #sql = #sql + #cr + N'EXEC sp_rename #objname = N'''
+ SCHEMA_NAME(schema_id) + '.'
+ REPLACE(name, '''', '''''') + ''', #newname = N''PK_'
+ LEFT(REPLACE(OBJECT_NAME(parent_object_id), '''', ''), #TableLimit) + ''';'
FROM sys.key_constraints
WHERE type = 'PK'
AND is_ms_shipped = 0;
END
Foreign Keys:
IF #ForeignKeys = 1
BEGIN
SELECT #sql = #sql + #cr + #cr + N'/* ---- Foreign Keys ---- */' + #cr;
SELECT #sql = #sql + #cr + N'EXEC sp_rename #objname = N'''
+ SCHEMA_NAME(f.schema_id) + '.'
+ REPLACE(f.name, '''', '''''') + ''', #newname = N''FK_'
+ LEFT(REPLACE(t.name, '''', ''), #TableLimit)
+ '_' + LEFT(REPLACE(t2.name, '''', ''), #TableLimit)
+ '_' + LEFT(REPLACE(c.name, '''', ''), #ColumnLimit)
+ ''';'
FROM
sys.foreign_keys as f
inner join sys.foreign_key_columns as fk on f.object_id = fk.constraint_object_id
inner join sys.tables as t on fk.parent_object_id = t.object_id
inner join sys.tables as t2 on fk.referenced_object_id = t2.object_id
inner join sys.columns as c on fk.parent_object_id = c.object_id and
fk.parent_column_id = c.column_id
WHERE f.is_ms_shipped = 0;
END
Unique constraints:
IF (#UniqueConstraints = 1 OR #Indexes = 1)
BEGIN
SELECT #sql = #sql + #cr + #cr + N'/* ---- Indexes / Unique Constraints ---- */' + #cr;
SELECT #sql = #sql + #cr + N'EXEC sp_rename #objname = N'''
+ CASE is_unique_constraint WHEN 0 THEN
QUOTENAME(REPLACE(OBJECT_NAME(i.[object_id]), '''', '''''')) + '.' ELSE '' END
+ QUOTENAME(REPLACE(i.name, '''', '''''')) + ''', #newname = N'''
+ CASE is_unique_constraint WHEN 1 THEN 'UQ_' ELSE 'IX_'
+ CASE is_unique WHEN 1 THEN 'U_' ELSE '' END
END + CASE has_filter WHEN 1 THEN 'F_' ELSE '' END
+ LEFT(REPLACE(OBJECT_NAME(i.[object_id]), '''', ''), #TableLimit)
+ '_' + STUFF((SELECT '_' + LEFT(REPLACE(c.name, '''', ''), #ColumnLimit)
FROM sys.columns AS c
INNER JOIN sys.index_columns AS ic
ON ic.column_id = c.column_id
AND ic.[object_id] = c.[object_id]
WHERE ic.[object_id] = i.[object_id]
AND ic.index_id = i.index_id
AND is_included_column = 0
ORDER BY ic.index_column_id FOR XML PATH(''),
TYPE).value('.', 'nvarchar(max)'), 1, 1, '') +''';'
FROM sys.indexes AS i
WHERE index_id > 0 AND is_primary_key = 0 AND type IN (1,2)
AND OBJECTPROPERTY(i.[object_id], 'IsMsShipped') = 0;
END
Default constraints:
IF #DefaultConstraints = 1
BEGIN
SELECT #sql = #sql + #cr + #cr + N'/* ---- DefaultConstraints ---- */' + #cr;
SELECT #sql = #sql + #cr + N'EXEC sp_rename #objname = N'''
+ SCHEMA_NAME(schema_id) + '.'
+ REPLACE(dc.name, '''', '''''') + ''', #newname = N''DF_'
+ LEFT(REPLACE(OBJECT_NAME(dc.parent_object_id), '''',''), #TableLimit)
+ '_' + LEFT(REPLACE(c.name, '''', ''), #ColumnLimit) + ''';'
FROM sys.default_constraints AS dc
INNER JOIN sys.columns AS c
ON dc.parent_object_id = c.[object_id]
AND dc.parent_column_id = c.column_id
AND dc.is_ms_shipped = 0;
END
Check Constraints:
IF #CheckConstraints = 1
BEGIN
SELECT #sql = #sql + #cr + #cr + N'/* ---- CheckConstraints ---- */' + #cr;
SELECT #sql = #sql + #cr + N'EXEC sp_rename #objname = N'''
+ SCHEMA_NAME(schema_id) + '.'
+ REPLACE(cc.name, '''', '''''') + ''', #newname = N''CK_'
+ LEFT(REPLACE(OBJECT_NAME(cc.parent_object_id), '''',''), #TableLimit)
+ '_' + LEFT(REPLACE(c.name, '''', ''), #ColumnLimit) + ''';'
FROM sys.check_constraints AS cc
INNER JOIN sys.columns AS c
ON cc.parent_object_id = c.[object_id]
AND cc.parent_column_id = c.column_id
AND cc.is_ms_shipped = 0;
END
SELECT #sql;
IF #SELECT_Only = 0 AND #sql > N''
BEGIN
EXEC sp_executesql #sql;
END
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)
Given a number, how do I discover in what table and column it could be found within?
I don't care if it's fast, it just needs to work.
This might help you. - from Narayana Vyas. It searches all columns of all tables in a given database. I have used it before and it works.
This is the Stored Proc from the above link - the only change I made was substituting the temp table for a table variable so you don't have to remember to drop it each time.
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT
DECLARE #Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
SET #TableName = ''
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
WHILE #TableName IS NOT NULL
BEGIN
SET #ColumnName = ''
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
To execute the stored procedure :
EXEC SearchAllTables 'YourStringHere'
If you need to run such search only once then you can probably go with any of the scripts already shown in other answers. But otherwise, I’d recommend using ApexSQL Search for this. It’s a free SSMS addin and it really saved me a lot of time.
Before running any of the scripts you should customize it based on the data type you want to search. If you know you are searching for datetime column then there is no need to search through nvarchar columns. This will speed up all of the queries above.
Based on bnkdev's answer I modified Narayana's Code to search all columns even numeric ones.
It'll run slower, but this version actually finds all matches not just those found in text columns.
I can't thank this guy enough. Saved me days of searching by hand!
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
SET #TableName = ''
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
WHILE #TableName IS NOT NULL
BEGIN
SET #ColumnName = ''
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(CONVERT(varchar(max), ' + #ColumnName + '), 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE CONVERT(varchar(max), ' + #ColumnName + ') LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
This is my independent take on this question that I use for my own work. It works in SQL2000 and greater, allows wildcards, column filtering, and will search most of the normal data types.
A pseudo-code description could be select * from * where any like 'foo'
--------------------------------------------------------------------------------
-- Search all columns in all tables in a database for a string.
-- Does not search: image, sql_variant or user-defined types.
-- Exact search always for money and smallmoney; no wildcards for matching these.
--------------------------------------------------------------------------------
declare #SearchTerm nvarchar(4000) -- Can be max for SQL2005+
declare #ColumnName sysname
--------------------------------------------------------------------------------
-- SET THESE!
--------------------------------------------------------------------------------
set #SearchTerm = N'foo' -- Term to be searched for, wildcards okay
set #ColumnName = N'' -- Use to restrict the search to certain columns, wildcards okay, null or empty string for all cols
--------------------------------------------------------------------------------
-- END SET
--------------------------------------------------------------------------------
set nocount on
declare #TabCols table (
id int not null primary key identity
, table_schema sysname not null
, table_name sysname not null
, column_name sysname not null
, data_type sysname not null
)
insert into #TabCols (table_schema, table_name, column_name, data_type)
select t.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE
from INFORMATION_SCHEMA.TABLES t
join INFORMATION_SCHEMA.COLUMNS c on t.TABLE_SCHEMA = c.TABLE_SCHEMA
and t.TABLE_NAME = c.TABLE_NAME
where 1 = 1
and t.TABLE_TYPE = 'base table'
and c.DATA_TYPE not in ('image', 'sql_variant')
and c.COLUMN_NAME like case when len(#ColumnName) > 0 then #ColumnName else '%' end
order by c.TABLE_NAME, c.ORDINAL_POSITION
declare
#table_schema sysname
, #table_name sysname
, #column_name sysname
, #data_type sysname
, #exists nvarchar(4000) -- Can be max for SQL2005+
, #sql nvarchar(4000) -- Can be max for SQL2005+
, #where nvarchar(4000) -- Can be max for SQL2005+
, #run nvarchar(4000) -- Can be max for SQL2005+
while exists (select null from #TabCols) begin
select top 1
#table_schema = table_schema
, #table_name = table_name
, #exists = 'select null from [' + table_schema + '].[' + table_name + '] where 1 = 0'
, #sql = 'select ''' + '[' + table_schema + '].[' + table_name + ']' + ''' as TABLE_NAME, * from [' + table_schema + '].[' + table_name + '] where 1 = 0'
, #where = ''
from #TabCols
order by id
while exists (select null from #TabCols where table_schema = #table_schema and table_name = #table_name) begin
select top 1
#column_name = column_name
, #data_type = data_type
from #TabCols
where table_schema = #table_schema
and table_name = #table_name
order by id
-- Special case for money
if #data_type in ('money', 'smallmoney') begin
if isnumeric(#SearchTerm) = 1 begin
set #where = #where + ' or [' + #column_name + '] = cast(''' + #SearchTerm + ''' as ' + #data_type + ')' -- could also cast the column as varchar for wildcards
end
end
-- Special case for xml
else if #data_type = 'xml' begin
set #where = #where + ' or cast([' + #column_name + '] as nvarchar(max)) like ''' + #SearchTerm + ''''
end
-- Special case for date
else if #data_type in ('date', 'datetime', 'datetime2', 'datetimeoffset', 'smalldatetime', 'time') begin
set #where = #where + ' or convert(nvarchar(50), [' + #column_name + '], 121) like ''' + #SearchTerm + ''''
end
-- Search all other types
else begin
set #where = #where + ' or [' + #column_name + '] like ''' + #SearchTerm + ''''
end
delete from #TabCols where table_schema = #table_schema and table_name = #table_name and column_name = #column_name
end
set #run = 'if exists(' + #exists + #where + ') begin ' + #sql + #where + ' print ''' + #table_name + ''' end'
print #run
exec sp_executesql #run
end
set nocount off
I don't put it in proc form since I don't want to maintain it across hundreds of DBs and it's really for ad-hoc work anyway. Please feel free to comment on bug-fixes.
I optimized Allain Lalonde answer (https://stackoverflow.com/a/436676/412368).
Numeric values are still supported. Should be roughly 4-5 times faster (1:03 vs 4:30), tested on a desktop with a 7GB database. http://developer.azurewebsites.net/2015/01/mssql-searchalltables/
IF OBJECT_ID ('dbo.SearchAllTables', 'P') IS NOT NULL
DROP PROCEDURE dbo.SearchAllTables;
GO
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Customized and modified: 2014-01-21
-- Tested on: SQL Server 2008 R2
DECLARE #Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256)
DECLARE #ColumnName nvarchar(128)
DECLARE #DataType nvarchar(128)
DECLARE #SearchStr2 nvarchar(110)
DECLARE #SearchDecimal decimal(38,19)
DECLARE #Query nvarchar(4000)
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%', '''')
SET #SearchDecimal = CASE WHEN ISNUMERIC(#SearchStr) = 1 THEN CONVERT(decimal(38,19), #SearchStr) ELSE NULL END
PRINT '#SearchStr2: ' + #SearchStr2
PRINT '#SearchDecimal: ' + CAST(#SearchDecimal AS nvarchar)
SET #TableName = ''
WHILE #TableName IS NOT NULL
BEGIN
SET #ColumnName = ''
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar',
'int', 'bigint', 'tinyint', 'numeric', 'decimal')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
SET #DataType =
(
SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND QUOTENAME(COLUMN_NAME) = #ColumnName
)
PRINT #TableName + '.' + #ColumnName + ' (' + #DataType + ')'
IF #ColumnName IS NOT NULL
BEGIN
IF #DataType IN ('int', 'bigint', 'tinyint', 'numeric', 'decimal')
BEGIN
IF #SearchDecimal IS NOT NULL
BEGIN
SET #Query = 'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(CAST(' + #ColumnName + ' AS nvarchar(110)), 3630) ' +
'FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' = ' + CAST(#SearchDecimal AS nvarchar)
PRINT ' ' + #Query
INSERT INTO #Results
EXEC (#Query)
END
END
ELSE
BEGIN
SET #Query = 'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) ' +
'FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
PRINT ' ' + #Query
INSERT INTO #Results
EXEC (#Query)
END
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
I have a solution from a while ago that I kept improving. Also searches within XML columns if told to do so, or searches integer values if providing a integer only string.
/* Reto Egeter, fullparam.wordpress.com */
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '%searchthis%' /* use LIKE syntax */
SET #FullRowResult = 1
SET #FullRowResultRows = 3
SET #SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET #SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET #SearchStrInXML = 0 /* Searching XML data may be slow */
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256) = '',#ColumnName nvarchar(128),#ColumnType nvarchar(20), #QuotedSearchStrColumnValue nvarchar(110), #QuotedSearchStrColumnName nvarchar(110)
SET #QuotedSearchStrColumnValue = QUOTENAME(#SearchStrColumnValue,'''')
DECLARE #ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))
WHILE #TableName IS NOT NULL
BEGIN
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE COALESCE(#SearchStrTableName,TABLE_NAME)
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
IF #TableName IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''' + #TableName + ''', 1)
AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE #SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN #SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + #SearchStrColumnName + '''' END + ',COLUMN_NAME)'
INSERT INTO #ColumnNameTable
EXEC (#sql)
WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM #ColumnNameTable)
BEGIN
PRINT #ColumnName
SELECT TOP 1 #ColumnName = COLUMN_NAME,#ColumnType = DATA_TYPE FROM #ColumnNameTable
SET #sql = 'SELECT ''' + #TableName + ''',''' + #ColumnName + ''',' + CASE #ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + #ColumnName + ' AS nvarchar(MAX)), 4096),'''
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + '),'''
ELSE 'LEFT(' + #ColumnName + ', 4096),''' END + #ColumnType + '''
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
INSERT INTO #Results
EXEC(#sql)
IF ##ROWCOUNT > 0 IF #FullRowResult = 1
BEGIN
SET #sql = 'SELECT TOP ' + CAST(#FullRowResultRows AS VARCHAR(3)) + ' ''' + #TableName + ''' AS [TableFound],''' + #ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
' FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
EXEC(#sql)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
Source:
http://fullparam.wordpress.com/2012/09/07/fck-it-i-am-going-to-search-all-tables-all-collumns/
It's my way to resolve this question. Tested on SQLServer2008R2
CREATE PROC SearchAllTables
#SearchStr nvarchar(100)
AS
BEGIN
DECLARE #dml nvarchar(max) = N''
IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE dbo.#Results
CREATE TABLE dbo.#Results
([tablename] nvarchar(100),
[ColumnName] nvarchar(100),
[Value] nvarchar(max))
SELECT #dml += ' SELECT ''' + s.name + '.' + t.name + ''' AS [tablename], ''' +
c.name + ''' AS [ColumnName], CAST(' + QUOTENAME(c.name) +
' AS nvarchar(max)) AS [Value] FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) +
' (NOLOCK) WHERE CAST(' + QUOTENAME(c.name) + ' AS nvarchar(max)) LIKE ' + '''%' + #SearchStr + '%'''
FROM sys.schemas s JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.types ty ON c.system_type_id = ty.system_type_id AND c .user_type_id = ty .user_type_id
WHERE t.is_ms_shipped = 0 AND ty.name NOT IN ('timestamp', 'image', 'sql_variant')
INSERT dbo.#Results
EXEC sp_executesql #dml
SELECT *
FROM dbo.#Results
END
Thanks for the really useful script.
You may need to add the following modification to the code if your tables have non-convertable fields:
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE NOT IN ('text', 'image', 'ntext')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
Chris
Here, very sweet and small solution:
1) create a store procedure:
create procedure get_table
#find_str varchar(50)
as
begin
declare #col_name varchar(500), #tab_name varchar(500);
declare #find_tab TABLE(table_name varchar(100), column_name varchar(100));
DECLARE tab_col cursor for
select C.name as 'col_name', T.name as tab_name
from sys.tables as T
left outer join sys.columns as C on C.object_id=T.object_id
left outer join sys.types as TP on C.system_type_id=TP.system_type_id
where type='U'
and TP.name in('text','ntext','varchar','char','nvarchar','nchar');
open tab_col
fetch next from tab_col into #col_name, #tab_name
while ##FETCH_STATUS = 0
begin
insert into #find_tab
exec('select ''' + #tab_name + ''',''' + #col_name + ''' from ' + #tab_name +
' where ' + #col_name + '=''' + #find_str + ''' group by ' +
#col_name + ' having count(*)>0');
fetch next from tab_col into #col_name, #tab_name;
end
CLOSE tab_col;
DEALLOCATE tab_col;
select table_name, column_name from #find_tab;
end
==========================
2) call procedure by calling store procedure:
exec get_table 'serach_string';
If you have phpMyAdmin installed use its Search feature.
Select your DataBase.
Be sure you do have selected DataBase, not a table, otherwise you'll get a completely different search dialog.
Click Search tab
List item Choose the search term you want
Choose the tables to search
Another way using JOIN and CURSOR:
USE My_Database;
-- Store results in a local temp table so that. I'm using a
-- local temp table so that I can access it in SP_EXECUTESQL.
create table #tmp (
tbl nvarchar(max),
col nvarchar(max),
val nvarchar(max)
);
declare #tbl nvarchar(max);
declare #col nvarchar(max);
declare #q nvarchar(max);
declare #search nvarchar(max) = 'my search key';
-- Create a cursor on all columns in the database
declare c cursor for
SELECT tbls.TABLE_NAME, cols.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLES AS tbls
JOIN INFORMATION_SCHEMA.COLUMNS AS cols
ON tbls.TABLE_NAME = cols.TABLE_NAME
-- For each table and column pair, see if the search value exists.
open c
fetch next from c into #tbl, #col
while ##FETCH_STATUS = 0
begin
-- Look for the search key in current table column and if found add it to the results.
SET #q = 'INSERT INTO #tmp SELECT ''' + #tbl + ''', ''' + #col + ''', ' + #col + ' FROM ' + #tbl + ' WHERE ' + #col + ' LIKE ''%' + #search + '%'''
EXEC SP_EXECUTESQL #q
fetch next from c into #tbl, #col
end
close c
deallocate c
-- Get results
select * from #tmp
-- Remove local temp table.
drop table #tmp
You might need to build an inverted index for your database. It is assured to be pretty fast.
-- exec pSearchAllTables 'M54*'
ALTER PROC pSearchAllTables (#SearchStr NVARCHAR(100))
AS
BEGIN
-- A procedure to search all tables in a database for a value
-- Note: Use * or % for wildcard
DECLARE
#Results TABLE([Schema.Table.ColumnName] NVARCHAR(370), ColumnValue NVARCHAR(3630))
SET NOCOUNT ON
DECLARE
#TableName NVARCHAR(256) = ''
, #ColumnName NVARCHAR(128)
, #SearchStr2 NVARCHAR(110) = QUOTENAME(REPLACE(#SearchStr, '*', '%'), '''')
WHILE #TableName IS NOT NULL
BEGIN
SET #ColumnName = ''
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
SET #ColumnName =
(
SELECT MIN(QUOTENAME(COLUMN_NAME))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC ('SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) FROM ' + #TableName + ' (NOLOCK) WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2)
END
END
END
SELECT
[Schema.Table.ColumnName]
, ColumnValue
FROM #Results
GROUP BY
[Schema.Table.ColumnName]
, ColumnValue
END
For Development purpose you can just export the required tables data into a single HTML and make a direct search on it.
Suppose if you want to get all the table with name a column name contain logintime in the database MyDatabase below is the code sample
use MyDatabase
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%logintime%'
ORDER BY schema_name, table_name;
I was looking for a just a numeric value = 6.84 - using the other answers here I was able to limit my search to this
Declare #sourceTable Table(id INT NOT NULL IDENTITY PRIMARY KEY, table_name varchar(1000), column_name varchar(1000))
Declare #resultsTable Table(id INT NOT NULL IDENTITY PRIMARY KEY, table_name varchar(1000))
Insert into #sourceTable(table_name, column_name)
select schema_name(t.schema_id) + '.' + t.name as[table], c.name as column_name
from sys.columns c
join sys.tables t
on t.object_id = c.object_id
where type_name(user_type_id) in ('decimal', 'numeric', 'smallmoney', 'money', 'float', 'real')
order by[table], c.column_id;
DECLARE db_cursor CURSOR FOR
Select table_name, column_name from #sourceTable
DECLARE #mytablename VARCHAR(1000);
DECLARE #mycolumnname VARCHAR(1000);
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #mytablename, #mycolumnname
WHILE # #FETCH_STATUS = 0
BEGIN
Insert into #ResultsTable(table_name)
EXEC('SELECT ''' + #mytablename + '.' + #mycolumnname + ''' FROM ' + #mytablename + ' (NOLOCK) ' +
' WHERE ' + #mycolumnname + '=6.84')
FETCH NEXT FROM db_cursor INTO #mytablename, #mycolumnname
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
Select Distinct(table_name) from #ResultsTable
There are lots of workable answers already. I just wanted to share one I wrote that has additional functionality.
--=======================================================================
-- MSSQL Unified Search
-- Minimum compatibility level = 130 (SQL Server 2016)
-- NOTE: The minimum compatibility level is required by the built-in STRING_SPLIT() function.
-- However, you can create the STRING_SPLIT() function at the bottom of this script for
-- lower versions of MSSQL Server.
--
-- Usage:
-- Set the parameters below and execute this script.
--
/************************ Enter Parameters Here ************************/
/**/
/**/ DECLARE #SearchString VARCHAR(1000) = 'string to search for'; -- Accepts SQL wilcards
/**/
/**/ DECLARE #IncludeUserTables BIT = 1;
/**/ DECLARE #IncludeViews BIT = 0;
/**/ DECLARE #IncludeStoredProcedures BIT = 0;
/**/ DECLARE #IncludeFunctions BIT = 0;
/**/ DECLARE #IncludeTriggers BIT = 0;
/**/
/**/ DECLARE #DebugMode BIT = 0;
/**/ DECLARE #ExcludeColumnTypes NVARCHAR(500) = 'text, ntext, char, nchar, timestamp, bigint, tinyint, smallint, bit, date, time, smalldatetime, datetime, datetime2, real, money, float, decimal, binary, varbinary, image'; -- Comma delimited list
/**/
/***********************************************************************/
SET NOCOUNT ON;
SET #SearchString = QUOTENAME(#SearchString,'''');
DECLARE #Results TABLE ([ObjectType] NVARCHAR(200), [ObjectName] NVARCHAR(200), [ColumnName] NVARCHAR(400), [Value] NVARCHAR(MAX), [SelectStatement] NVARCHAR(1000));
DECLARE #ExcludeColTypes TABLE (system_type_id INT);
INSERT INTO #ExcludeColTypes ([system_type_id])
SELECT [system_type_id]
FROM sys.types WHERE
[name] IN (
SELECT LTRIM(RTRIM([value])) FROM STRING_SPLIT(#ExcludeColumnTypes,',')
);
DECLARE #ObjectType NVARCHAR(200);
DECLARE #ObjectName NVARCHAR(200);
DECLARE #Value NVARCHAR(MAX);
DECLARE #SelectStatement NVARCHAR(1000);
DECLARE #Query NVARCHAR(4000);
/********************* Table Objects *********************/
IF (#IncludeUserTables = 1)
BEGIN
DECLARE #TableObjectId INT = (SELECT MIN([object_id]) FROM sys.tables);
DECLARE #ColumnId INT;
WHILE #TableObjectId IS NOT NULL
BEGIN
SELECT #ObjectType = 'USER TABLE';
SELECT #ObjectName = '[' + SCHEMA_NAME([schema_id]) + '].[' + OBJECT_NAME(#TableObjectId) + ']' FROM sys.tables WHERE [object_id] = #TableObjectId;
SET #ColumnId = (SELECT MIN([column_id]) FROM sys.columns WHERE [system_type_id] NOT IN (SELECT [system_type_id] FROM #ExcludeColTypes) AND [object_id] = #TableObjectId);
WHILE #ColumnId IS NOT NULL
BEGIN
SELECT #Value = '[' + [name] +']' FROM sys.columns WHERE [object_id] = #TableObjectId AND column_id = #ColumnId;
SET #SelectStatement = 'SELECT * FROM ' + #ObjectName + ' WHERE CAST(' + #Value + ' AS NVARCHAR(4000)) LIKE ' + #SearchString + ';';
SET #Query = 'SELECT '
+ QUOTENAME(#ObjectType, '''')
+ ', ' + QUOTENAME(#ObjectName, '''')
+ ', ' + QUOTENAME(#Value, '''')
+ ', ' + #Value
+ ', ''' + REPLACE(#SelectStatement,'''','''''') + ''''
+ ' FROM ' + #ObjectName
+ ' WHERE CAST(' + #Value + ' AS NVARCHAR(4000)) LIKE ' + #SearchString + ';';
IF #DebugMode = 0
BEGIN
INSERT INTO #Results EXEC(#Query);
END;
ELSE
BEGIN
PRINT 'Select Statement: ' + #SelectStatement;
PRINT 'Query: ' + #Query;
END;
SET #ColumnId = (SELECT MIN([column_id]) FROM sys.columns WHERE [system_type_id] NOT IN (SELECT [system_type_id] FROM #ExcludeColTypes) AND [object_id] = #TableObjectId AND [column_id] > #ColumnId);
END;
SET #TableObjectId = (SELECT MIN([object_id]) FROM sys.tables WHERE [object_id] > #TableObjectId);
END;
END;
/********************* Objects Other than Tables *********************/
SET #Query = 'SELECT ' +
'ObjectType = CASE ' +
'WHEN b.[type] = ''V'' THEN ''VIEW'' ' +
'WHEN b.[type] = ''P'' THEN ''STORED PROCEDURE'' ' +
'WHEN b.[type] = ''FN'' THEN ''SCALAR-VALUED FUNCTION'' ' +
'WHEN b.[type] = ''IF'' THEN ''TABLE-VALUED FUNCTION'' ' +
'WHEN b.[type] = ''TR'' THEN ''TRIGGER'' ' +
'END ' +
',[ObjectName] = ''['' + SCHEMA_NAME(b.[schema_id]) + ''].['' + OBJECT_NAME(a.[object_id]) + '']'' ' +
',[ColumnName] = NULL ' +
',[Value] = a.[definition] ' +
',[SelectStatement] = ''SP_HELPTEXT '' + QUOTENAME(''['' + SCHEMA_NAME(b.[schema_id]) + ''].['' + OBJECT_NAME(a.[object_id]) + '']'','''''''') + '';'' ' +
'FROM [sys].[sql_modules] a ' +
'JOIN [sys].[objects] b ON a.[object_id] = b.[object_id] ' +
'WHERE ' +
'( ' +
' a.[definition] LIKE ' + #SearchString +
') ' +
'AND ' +
'( ' +
' ( ' +
CAST(#IncludeViews AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''V'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeStoredProcedures AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''P'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeFunctions AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''FN'',''IF'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeTriggers AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''TR'') ' +
' ) ' +
'); ';
IF #DebugMode = 0
BEGIN
INSERT INTO #Results EXEC(#Query);
END;
ELSE
BEGIN
PRINT 'Select Statement: ' + #SelectStatement;
PRINT 'Query: ' + #Query;
END;
IF #DebugMode = 0
BEGIN
SELECT
[ObjectType]
,[ObjectName]
,[ColumnName]
,[Value]
,[Count] = CASE
WHEN [ObjectType] IN ('USER TABLE') THEN COUNT(1)
ELSE NULL
END
,[SelectStatement]
FROM #Results
GROUP BY [ObjectType], [ObjectName], [ColumnName], [Value], [SelectStatement]
ORDER BY [Value];
END;
/********************** STRING_SPLIT() FUNCTION **********************
CREATE FUNCTION STRING_SPLIT (
#Expression nvarchar(4000)
,#Delimiter nvarchar(100)
)
RETURNS #Ret TABLE ([value] NVARCHAR(4000))
AS
BEGIN
DECLARE #Start INT = 0, #End INT, #Length INT;
SELECT #End = CHARINDEX(#Delimiter,#Expression), #Length = #End - #Start;
IF #End <= 0
BEGIN
INSERT INTO #Ret ([value]) VALUES (#Expression);
END
ELSE
BEGIN
WHILE #Length >= 0
BEGIN
INSERT INTO #Ret ([value])
SELECT ltrim(rtrim(substring(#Expression,#Start,#Length)));
SELECT #Start = #End + LEN(#Delimiter)
SELECT #End = CHARINDEX(#Delimiter,#Expression,#Start)
IF #End < 1
SELECT #End = LEN(#Expression) + 1;
SELECT #Length = #End - #Start;
END;
END;
RETURN;
END;
*********************************************************************/
By far the best and most universal solution I found is to pipe a dump of the db through to a grep of what you are searching for.
e.g. for Mysql:
mysqldump -pPASSWORD database | grep 'search phrase'
Or if you get too many results, you can then output them to a file:
mysqldump -pPASSWORD database | grep 'search phrase' > results.txt