I made some changes to the work of Gareth, which runs BTW, and I think it's great. I wanted to enable cloning of triggers and copy the contents of the tables. In essence, βcopyβ most of the table as far as I can with one shot. I have included the entire code snippet. Remember that this is not entirely original, and I do not claim to be a merit in any hard work of Gareth. Hope this is helpful for anyone interested.
CREATE PROCEDURE [dbo].[spCloneTableStructure] @SourceSchema nvarchar(255) , @SourceTable nvarchar(255) , @DestinationSchema nvarchar(255) , @DestinationTable nvarchar(255) , @RecreateIfExists bit = 0 AS BEGIN 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