Skip to content

Instantly share code, notes, and snippets.

@gekola
Created November 7, 2013 05:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gekola/7349204 to your computer and use it in GitHub Desktop.
Save gekola/7349204 to your computer and use it in GitHub Desktop.
TSQL deep table copy procedure example.
USE [AdventureWorks2012];
GO
ALTER PROCEDURE [dbo].[CopyTable]
@src_name nvarchar(4000)
, @dst_name nvarchar(4000)
AS
BEGIN
DECLARE @sql nvarchar(4000)
, @src_schema nvarchar(4000) = OBJECT_SCHEMA_NAME(OBJECT_ID(@src_name))
, @src_table nvarchar(4000) = OBJECT_NAME(OBJECT_ID(@src_name));
-- Copy data
SET @sql = 'SELECT * INTO ' + @dst_name + ' FROM ' + @src_name + ';';
EXEC (@sql);
DECLARE @constrs TABLE ([name] nvarchar(4000), [col] nvarchar(4000), [type] nvarchar(4000))
INSERT INTO @constrs
SELECT [c].[CONSTRAINT_NAME], [c].[COLUMN_NAME], [tk].[CONSTRAINT_TYPE]
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS [tk]
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE [c]
ON [tk].TABLE_NAME = @src_table
AND [tk].[TABLE_SCHEMA] = @src_schema
AND [c].[TABLE_NAME] = [tk].[TABLE_NAME]
AND [c].[TABLE_SCHEMA] = [tk].[TABLE_SCHEMA]
AND [c].[CONSTRAINT_NAME] = [tk].[CONSTRAINT_NAME]
WHERE [tk].[CONSTRAINT_TYPE] != N'FOREIGN KEY';
-- Copy PK
DECLARE @pkCol NVARCHAR(4000) = STUFF((
SELECT N',' + [col]
FROM @constrs
WHERE [type] = N'PRIMARY KEY'
FOR XML PATH(N'')), 1, 1, N'');
SET @sql = 'ALTER TABLE ' + @dst_name + ' ADD CONSTRAINT '
+ (SELECT TOP 1 name FROM @constrs WHERE [type] = N'PRIMARY KEY')
+ N' PRIMARY KEY (' + @pkCol + ');';
EXEC (@sql);
/* It seems there are no more constraints in @constrs.
* This fact is to be investigated.
*/
DECLARE @count int, @s int = 0;
DECLARE @name nvarchar(4000), @def nvarchar(4000), @col nvarchar(4000);
-- checks
DECLARE @constrs2 TABLE ([name] nvarchar(4000), [definition] nvarchar(4000));
INSERT INTO @constrs2
SELECT [name], [definition]
FROM [sys].[CHECK_CONSTRAINTS] [tk]
WHERE [tk].[parent_object_id] = OBJECT_ID(@src_name);
SELECT @count=COUNT(*) FROM @constrs2;
WHILE (@s < @count)
BEGIN
SELECT @name=[name], @def=[definition]
FROM @constrs2 ORDER BY [name] OFFSET @s ROWS FETCH NEXT 1 ROW ONLY;
EXEC(N'ALTER TABLE ' + @dst_name + N' ADD CONSTRAINT [' + @name + N'] CHECK ' + @def + N';');
SET @s = @s + 1;
END
-- Default value constraints
DECLARE @constrs3 TABLE ([name] nvarchar(4000)
, [definition] nvarchar(4000)
, [column] nvarchar(4000));
SET @s = 0;
INSERT INTO @constrs3
SELECT [tk].[name], [definition], [c].[name]
FROM [sys].[DEFAULT_CONSTRAINTS] [tk]
JOIN [sys].[columns] AS [c]
ON [tk].[parent_object_id] = [c].[object_id] AND [tk].[parent_column_id] = [c].[column_id]
WHERE [tk].[parent_object_id] = OBJECT_ID(@src_name);
SELECT @count=COUNT(*) FROM @constrs3;
WHILE (@s < @count)
BEGIN
SELECT @name=[name], @def=[definition], @col=[column]
FROM @constrs3 ORDER BY [name] OFFSET @s ROWS FETCH NEXT 1 ROW ONLY;
EXEC(N'ALTER TABLE ' + @dst_name + N' ADD CONSTRAINT [' + @name
+ N'] DEFAULT ' + @def + N' FOR [' + @col + N'];');
SET @s = @s + 1;
END
-- Default indexes
DECLARE @indexes TABLE ([id] int);
SET @s = 0;
INSERT INTO @indexes
SELECT [index_id]
FROM [sys].[indexes] [tk]
WHERE [tk].[object_id] = OBJECT_ID(@src_name)
AND [tk].[is_primary_key] = 0
AND [tk].[is_unique_constraint] = 0;
SELECT @count=COUNT(*) FROM @indexes;
WHILE (@s < @count)
BEGIN
DECLARE @index_id int
, @unique nvarchar(7) -- UNIQUE
, @clustered nvarchar(13) -- NONCLUSTERED
, @is_padded nvarchar(4) -- PAD_INDEX = OFF
-- STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF
, @ignore_dup_key nvarchar(4) -- IGNORE_DUP_KEY = OFF
-- DROP_EXISTING = OFF, ONLINE = OFF
, @allow_row_locks nvarchar(4) -- ALLOW_ROW_LOCKS = ON
, @allow_page_locks nvarchar(4) -- ALLOW_PAGE_LOCKS = ON
;
SELECT @name=[name], @index_id=[index_id]
, @unique = CASE WHEN ([is_unique] = 1) THEN N'UNIQUE' ELSE N'' END
, @clustered = [type_desc]
, @is_padded = CASE WHEN ([is_padded] = 1) THEN N'ON' ELSE N'OFF' END
, @ignore_dup_key = CASE WHEN ([ignore_dup_key] = 1) THEN N'ON' ELSE N'OFF' END
, @allow_row_locks = CASE WHEN ([allow_row_locks] = 1) THEN N'ON' ELSE N'OFF' END
, @allow_page_locks = CASE WHEN ([allow_page_locks] = 1) THEN N'ON' ELSE N'OFF' END
FROM [sys].[indexes] INNER JOIN @indexes [i] ON [i].[id] = [index_id]
WHERE [sys].[indexes].[object_id] = OBJECT_ID(@src_name)
ORDER BY [i].[id] OFFSET @s ROWS FETCH NEXT 1 ROW ONLY;
SET @col = STUFF((
SELECT N',[' + [c].[name] + N'] '
+ CASE WHEN ([ctk].[is_descending_key] != 0) THEN N'DESC' ELSE N'ASC' END
FROM [sys].[index_columns] [ctk]
INNER JOIN [sys].[columns] [c]
ON [c].[object_id] = [ctk].[object_id] AND [c].[column_id] = [ctk].[column_id]
WHERE [ctk].[object_id] = OBJECT_ID(@src_name)
AND [ctk].[index_id] = @index_id
FOR XML PATH(N'')
), 1, 1, N'');
EXEC(N'CREATE ' + @unique + N' ' + @clustered + N' INDEX ' + @name
+ N' ON ' + @dst_name + N' (' + @col + N') WITH (PAD_INDEX = ' + @is_padded
+ N', STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = ' + @ignore_dup_key
+ N', DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ' + @allow_row_locks
+ N', ALLOW_PAGE_LOCKS = ' + @allow_page_locks + N') ON [PRIMARY]');
SET @s += 1;
END
END
GO
IF (OBJECT_ID(N'dbo.dest1') IS NOT NULL) DROP TABLE [dbo].[dest1];
GO
EXEC [dbo].[CopyTable] @src_name=N'[HumanResources].[Employee]', @dst_name=N'[dbo].[dest1]';
GO
@gekola
Copy link
Author

gekola commented Nov 7, 2013

Triggers copy does not seem reasonable due to target table is often referred by name from there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment