CREATE PROCEDURE dbo.usp_CloneDBData -- table schemas must be identical
@srcdb AS VARCHAR(1000),
@dstdb AS VARCHAR(1000)
AS
--DECLARE @srcdb AS VARCHAR(1000)
--DECLARE @dstdb AS VARCHAR(1000)
--SET @srcdb = '[_test1]'
--SET @dstdb = '_test2'
DECLARE @allsql AS NVARCHAR(4000)
SET @srcdb = '[' + REPLACE(REPLACE(@srcdb,'[',''),']','') + ']'
SET @dstdb = '[' + REPLACE(REPLACE(@dstdb,'[',''),']','') + ']'
IF (@srcdb = @dstdb)
BEGIN
RAISERROR ('Source and Destination Databases cannot be the same', 16, 1)
RETURN
END
SET @allsql = '
-- truncate and refill from an identical table in another database
EXEC '+@dstdb+'.dbo.sp_msforeachtable ''ALTER TABLE ? NOCHECK CONSTRAINT all''
DECLARE cur CURSOR FOR
SELECT table_name, table_schema
FROM '+@srcdb+'.INFORMATION_SCHEMA.tables tab
WHERE table_type = ''BASE TABLE''
OPEN cur
DECLARE @tablename VARCHAR(255) ,@tableschema VARCHAR(255)
FETCH NEXT FROM cur INTO @tablename, @tableschema
WHILE ( @@FETCH_STATUS <> -1 )
BEGIN
IF ( @@FETCH_STATUS <> -2 )
DECLARE @sqltxt NVARCHAR(4000)
DECLARE @columnlist VARCHAR(4000)
Select @columnlist = ISNULL(Stuff(
(
Select '', '' + C.COLUMN_NAME
From [_Test1].INFORMATION_SCHEMA.COLUMNS As C
Where C.TABLE_SCHEMA = T.TABLE_SCHEMA
And C.TABLE_NAME = T.TABLE_NAME
Order By C.ORDINAL_POSITION
For Xml Path('''')
), 1, 2, '''') ,'''')
From [_Test1].INFORMATION_SCHEMA.TABLES As T
WHERE T.TABLE_NAME = @tablename
SET @sqltxt = N''''
EXEC dbo.sp_executesql @sqltxt
SET @sqltxt = N''
use '+@dstdb+';
DELETE ['' + @tableschema + ''].['' + @tablename + ''];
IF ((SELECT OBJECTPROPERTY( OBJECT_ID(N''''['' + @tableschema + ''].['' + @tablename + '']''''), ''''TableHasIdentity'''')) = 1) SET IDENTITY_INSERT ['' + @tableschema + ''].['' + @tablename + ''] ON;
INSERT INTO ['' + @tableschema + ''].['' + @tablename + ''] (''+@columnlist+'') SELECT ''+@columnlist+'' FROM [_Test1].['' + @tableschema + ''].['' + @tablename + ''];
IF ((SELECT OBJECTPROPERTY( OBJECT_ID(N''''['' + @tableschema + ''].['' + @tablename + '']''''), ''''TableHasIdentity'''')) = 1) SET IDENTITY_INSERT ['' + @tableschema + ''].['' + @tablename + ''] OFF;
''
EXEC dbo.sp_executesql @sqltxt
FETCH NEXT FROM cur INTO @tablename, @tableschema
END
CLOSE cur
DEALLOCATE cur
exec '+@dstdb+'.dbo.sp_msforeachtable ''ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all''
'
BEGIN TRY
BEGIN TRAN
EXEC dbo.sp_executesql @allsql
COMMIT TRAN
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
--DECLARE @ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY()
--,@ErrorState = ERROR_STATE();
RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
1 -- State.
);
ROLLBACK TRAN
END CATCH
Monday, April 30, 2012
I updated my previous entry as a stored procedure with error catching and rollback.
usage:
EXEC dbo.usp_CloneDBData @srcdb, @dstdb -- Source and Destination database names respectively. This version does not work using linked servers, but could easily be modified to do so.
Thursday, April 26, 2012
SQL Server TSQL script to clone a database's tables and data
the following script will create two dissimilar databases for demonstration purposes, insert different data into them, identify the schema differences, drop the tables that are different out of the destination database, create and execute scripts to create all missing tables, truncate the tables in the destination database, then insert all data from all tables in the source into the tables in the destination.
to do a find replace: _test1 is the source, _test2 is the destination
you do not need the last 6 select statements or anything above the comment "-- find any schema differences between tables and drop"
USE master
go
CREATE DATABASE [_Test1]
go
CREATE DATABASE [_Test2]
go
USE [_Test1]
go
CREATE TABLE tbl1
(
col1 INT NULL,
col2 VARCHAR(1) NULL,
col3 bit NULL,
col4 float NULL,
col5 NUMERIC(18,5) NULL
)
GO
CREATE TABLE tbl2
(
col1 INT NULL,
col2 INT NULL,
col3 INT NULL,
col4 INT NULL,
col5 INT NULL
)
GO
CREATE TABLE tbl3
(
col1 INT NULL,
col2 INT NULL,
col3 INT NULL,
col4 INT NULL,
col5 INT NULL
)
GO
INSERT dbo.tbl1 (col1,col2,col3,col4,col5) VALUES (1,2,3,4,5)
INSERT dbo.tbl2 (col1,col2,col3,col4,col5) VALUES (1,2,3,4,5)
INSERT dbo.tbl3 (col1,col2,col3,col4,col5) VALUES (1,2,3,4,5)
go
USE [_Test2]
go
CREATE TABLE tbl1
(
col1 INT NULL,
col2 VARCHAR(1) NULL,
col3 bit NULL,
col4 float NULL,
col5 NUMERIC(18,5) NULL
)
GO
CREATE TABLE tbl2
(
col1 INT NULL,
col2 INT NULL,
col3 INT NULL,
col4 INT NULL
)
GO
----CREATE TABLE tbl3
----(
---- col1 INT NULL,
---- col2 INT NULL,
---- col3 INT NULL,
---- col4 INT NULL,
---- col5 INT NULL
----)
----GO
INSERT dbo.tbl1 (col1,col2,col3,col4,col5) VALUES (1,2,3,4,6)
INSERT dbo.tbl1 (col1,col2,col3,col4,col5) VALUES (1,2,3,4,7)
go
-- tables are different
SELECT * FROM [_test1].dbo.tbl1
SELECT * FROM [_test2].dbo.tbl1
SELECT * FROM [_test1].dbo.tbl2
SELECT * FROM [_test2].dbo.tbl2
SELECT * FROM [_test1].dbo.tbl3
--SELECT * FROM [_test2].dbo.tbl3 -- this one produces an error. the table does not exist
go
USE [_Test1]
go
-- find any schema differences between tables and drop
DECLARE @sqltxt NVARCHAR(4000)
SELECT @sqltxt = STUFF((
SELECT DISTINCT ';DROP TABLE [_Test2].[' + t2.TABLE_SCHEMA + '].[' + t2.TABLE_NAME + ']'
FROM [_Test1].information_schema.COLUMNS c1
LEFT JOIN [_Test2].information_schema.tables t2 ON c1.TABLE_SCHEMA = t2.TABLE_SCHEMA AND c1.TABLE_NAME = t2.TABLE_NAME
FULL OUTER JOIN [_Test2].information_schema.COLUMNS c2 ON
c1.TABLE_SCHEMA = c2.TABLE_SCHEMA
AND c1.TABLE_NAME = c2.TABLE_NAME
AND c1.COLUMN_NAME = c2.COLUMN_NAME
WHERE
( ISNULL(c1.COLUMN_NAME,'') != ISNULL(c2.COLUMN_NAME,'') or
ISNULL(c1.IS_NULLABLE,'') != ISNULL(c2.IS_NULLABLE,'') or
ISNULL(c1.DATA_TYPE,'') != ISNULL(c2.DATA_TYPE,'') or
ISNULL(c1.NUMERIC_PRECISION,99) != ISNULL(c2.NUMERIC_PRECISION,99) or
ISNULL(c1.NUMERIC_SCALE,-1) != ISNULL(c2.NUMERIC_SCALE,-1) or
ISNULL(c1.CHARACTER_MAXIMUM_LENGTH,-1) != ISNULL(c2.CHARACTER_MAXIMUM_LENGTH,-1) or
ISNULL(c1.COLUMN_DEFAULT,'') != ISNULL(c2.COLUMN_DEFAULT,'') )
AND t2.TABLE_NAME IS NOT NULL
FOR XML PATH('')), 1, 1, '')
EXECUTE [_Test2].dbo.sp_executesql @sqltxt
go
-- generate script to create any missing tables
DECLARE @sqltxt NVARCHAR(4000)
SELECT @sqltxt = STUFF((
select ';create table [_Test2].[' + so.TABLE_SCHEMA + '].[' + so.TABLE_NAME + '] (' + o.list + ')' + CASE WHEN tc.Constraint_Name IS NULL THEN '' ELSE 'ALTER TABLE ' + so.TABLE_NAME + ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ')' END
from INFORMATION_SCHEMA.tables so
JOIN (
SELECT t1.TABLE_SCHEMA, t1.TABLE_NAME
FROM [_Test1].information_schema.tables t1
LEFT JOIN [_Test2].information_schema.tables t2 ON t1.TABLE_SCHEMA = t2.TABLE_SCHEMA AND t1.TABLE_NAME = t2.TABLE_NAME
WHERE t2.TABLE_NAME IS NULL
) list ON so.TABLE_SCHEMA = list.TABLE_SCHEMA AND so.TABLE_NAME = list.TABLE_NAME
cross apply
(SELECT
'['+column_name+'] ' +
data_type + case data_type
when 'sql_variant' then ''
when 'text' then ''
when 'decimal' then '(' + cast(numeric_precision_radix as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
when 'numeric' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
else coalesce('('+case when character_maximum_length = -1 then 'MAX' else cast(character_maximum_length as varchar) end +')','') end + ' ' +
case when exists (
select id from syscolumns
where object_name(id)=so.TABLE_NAME
and name=column_name
and columnproperty(id,name,'IsIdentity') = 1
) then
'IDENTITY(' +
cast(ident_seed(so.TABLE_NAME) as varchar) + ',' +
cast(ident_incr(so.TABLE_NAME) as varchar) + ')'
else ''
end + ' ' +
(case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT ELSE '' END + ', '
from information_schema.columns where table_name = so.TABLE_NAME
order by ordinal_position
FOR XML PATH('')) o (list)
left join
information_schema.table_constraints tc
on tc.Table_name = so.TABLE_NAME
AND tc.Constraint_Type = 'PRIMARY KEY'
cross apply
(select '[' + Column_Name + '], '
FROM information_schema.key_column_usage kcu
WHERE kcu.Constraint_Name = tc.Constraint_Name
ORDER BY
ORDINAL_POSITION
FOR XML PATH('')) j (list)
FOR XML PATH('')), 1, 1, '')
EXECUTE [_Test2].dbo.sp_executesql @sqltxt
go
-- truncate and refill from an identical table in another database
DECLARE cur CURSOR FOR
SELECT table_name, table_schema
FROM [_Test1].INFORMATION_SCHEMA.tables tab
WHERE table_type = 'BASE TABLE'
OPEN cur
DECLARE @tablename VARCHAR(255) ,@tableschema VARCHAR(255)
FETCH NEXT FROM cur INTO @tablename, @tableschema
WHILE ( @@FETCH_STATUS <> -1 )
BEGIN
IF ( @@FETCH_STATUS <> -2 )
DECLARE @sqltxt NVARCHAR(255)
SET @sqltxt = N'TRUNCATE TABLE [_Test2].[' + @tableschema + '].[' + @tablename + ']; INSERT INTO [_Test2].[' + @tableschema + '].[' + @tablename + '] SELECT * FROM [_Test1].[' + @tableschema + '].[' + @tablename + ']'
EXEC dbo.sp_executesql @sqltxt
FETCH NEXT FROM cur INTO @tablename, @tableschema
END
CLOSE cur
DEALLOCATE cur
go
--tables ARE identical
SELECT * FROM [_test1].dbo.tbl1
SELECT * FROM [_test2].dbo.tbl1
SELECT * FROM [_test1].dbo.tbl2
SELECT * FROM [_test2].dbo.tbl2
SELECT * FROM [_test1].dbo.tbl3
SELECT * FROM [_test2].dbo.tbl3
Subscribe to:
Posts (Atom)