SQL Server procedure to script tables
In the SSMS you can generate CREATE statements per object by using the object context menu, or generate CREATE statements for multiple objects by using the "Generate script" wizard.
To generate CREATE statements of objects by using T-SQL is not natively implemented in the SSMS. However the system table sys.sql_modules contains the CREATE statements of procedures, functions, triggers and views. It's not that hard to derive that code and dump it to files.
I always wanted to script tables too, in a way SSMS can do it for me. I searched in several blogs for a way to script tables. Most of the solutions are scripts that extract definitions from sys tables, but they all had flaws. How does SSMS do it? Well it uses dll's on the background. You can use them in Powershell by yourself too, but I like to keep everything on board of a procedure. So I created two procedures (dbo.prc_script_tables_multi and dbo.prc_script_tables_one) to script tables to files. The first one scripts every table (of a given database) to an individual file, the second one scripts all tables to one file. Both procedures create a temporarily Powershell script, launches it, and will be deleted afterwards. The Powershell script delivers the scriptfile(s) to the given path.
The Powershell script is based on this blog thread:
https://blogs.msdn.microsoft.com/buckwoody/2009/07/02/powershell-and-sql-server-script-all-tables/
Documentation of the Microsoft.SqlServer.Management.Smo ScriptingOptions Class
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.scriptingoptions.aspx
The two main procedures use 2 functions (dbo.fun_FolderExist and dbo.fun_FileExist) and 1 other procedure (dbo.prc_save_text_to_file) all are in the source code. Also OLE Automation and xp_cmdshell has to be enabled on the server.
The current settings produce (in my opinion) a normal CREATE TABLE script. Only the IF NOT EXISTS BEGIN END block addition can be influenced by the parameter @includeifnotexists.
With a little tweaking it is possible to change the procedure to your own wishes.
Remember to always test new procedures on a test environment.
Happy computing!
Gerrit Mantel, LUMC, The Netherlands
Comments for the main procedures
SQL Server procedure dbo.prc_script_tables_multi
Purpose:
Script all tables for a given database to individual script files on a given path.
Parameters:
@dbname NVARCHAR(128), default '', Database name
@path VARCHAR(265), default '', Path to dump scripts to
@includeifnotexist BIT, default False, Include "IF NOT EXIST {table} BEGIN ... END" logics surrounding CREATE TABLE statement.
Notes:
Database must be on current server.
Path to dump files to must exist, and you must have read and write permissions.
The script files will be created on the path: @path\@dbname\TABLE
The filenames are in format [{schema}].[{tablename}].sql
Illegal DOS filename characters in tablenames will cause the powershell script to fail: \ / : * ? " < > |
Examples:
EXEC dbo.prc_script_tables_multi @dbname='PROG', @path='C:\Data\Prog';
EXEC dbo.prc_script_tables_multi @dbname='PROG', @path='C:\Data\Prog', @includeifnotexists=1;
Used objects:
- dbo.fun_FolderExist (User Defined-Function in local database).
- dbo.fun_FileExist (User Defined-Function in local database).
- dbo.prc_save_text_to_file (Stored procedure in local database)
SQLServer configuration:
- OLE Automation has to be enabled.
- xp_cmdshell has to be enabled
SQL Server procedure dbo.prc_script_tables_one
Purpose:
Script all tables for a given database to one script file on a given path
Parameters:
@dbname NVARCHAR(128), default '', Database name
@path VARCHAR(265), default '', Path to dump scripts to
@includeifnotexist BIT, default False, Include "IF NOT EXIST {table} BEGIN ... END" logics surrounding CREATE TABLE statement.
Notes:
Database must be on current server.
Path to dump file to must exist, and you must have read and write permissions.
The script file that will be created is: @path\@dbname$TABLE.sql
Examples:
EXEC dbo.prc_script_tables_one @dbname='PROG', @path='C:\Data\Prog';
EXEC dbo.prc_script_tables_one @dbname='PROG', @path='C:\Data\Prog', @includeifnotexists=1;
Used objects:
- dbo.fun_FolderExist (User Defined-Function in local database).
- dbo.fun_FileExist (User Defined-Function in local database).
- dbo.prc_save_text_to_file (Stored procedure in local database)
SQLServer configuration:
- OLE Automation has to be enabled.
- xp_cmdshell has to be enabled
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fun_FolderExist] (
@dirname VARCHAR(265))
RETURNS INT
AS
BEGIN
/*
SQLServer User-Defined Function
PURPOSE
Check if folder exists.
The function returns 0 (folder does not exist), or 1 (folder exists).
EXAMPLES
SELECT dbo.fun_FolderExist('C:\Program Files')
1
SELECT dbo.fun_FolderExist('C:\xxxx')
0
HISTORY
24-nov-2015 - Created by Gerrit Mantel
TAGS
<program>
<description>Check if folder exists</description>
<generic>1</generic>
<author>Gerrit Mantel</author>
<created>2015-11-24</created>
<lastmodified>2015-11-24</lastmodified>
</program>
*/ DECLARE @fso INT
DECLARE @hr INT
DECLARE @ofolder INT
DECLARE @name VARCHAR(265)
DECLARE @result INT
EXEC @hr = sp_OACreate 'Scripting.FileSystemObject', @fso OUT;
EXEC @hr = sp_OAMethod @fso, 'FolderExists', @ofolder OUT, @dirname;
EXEC @hr = sp_OADestroy @fso;
SET @result = @ofolder;
RETURN @result;
END
GO
CREATE FUNCTION [dbo].[fun_FileExist] (
@filename VARCHAR(265))
RETURNS INT
AS
BEGIN
/*
SQLServer User-Defined Function
PURPOSE
Check if file exists.
The function returns 0 (file does not exist), or 1 (file exists).
EXAMPLES
SELECT dbo.fun_FileExist('C:\oneTouch_drive.cvf')
1
SELECT dbo.fun_FileExist('C:\xxxx.txt')
0
HISTORY
24-nov-2015 - Created by Gerrit Mantel
TAGS
<program>
<description>Check if file exists</description>
<generic>1</generic>
<author>Gerrit Mantel</author>
<created>2015-11-24</created>
<lastmodified>2015-11-24</lastmodified>
</program>
*/ DECLARE @fso INT
DECLARE @hr INT
DECLARE @ofile INT
DECLARE @result INT
EXEC @hr = sp_OACreate 'Scripting.FileSystemObject', @fso OUT;
EXEC @hr = sp_OAMethod @fso, 'FileExists', @ofile OUT, @filename;
EXEC @hr = sp_OADestroy @fso;
SET @result = @ofile;
RETURN @result;
END
GO
CREATE PROCEDURE [dbo].[prc_save_text_to_file] (
@text VARCHAR(MAX),
@filename VARCHAR(265))
AS
BEGIN
/*
SQLServer Stored Procedure
PURPOSE
Write text variable to file.
OLE Automation Procedures has to be enabled.
Existing files will be overwritten.
If path does not exist, no error is raised. Check path before with function fun_FolderExist.
If file could not be created, no error is raised. Check file afterwards with function fun_FileExist.
Latin-1 character set is used, 1 byte per character.
Parameters
@text VARCHAR(MAX) = (nonbinary) text
@filename VARCHAR(265) = filespec
Check path
HISTORY
25-jan-2017: Created by Gerrit Mantel
31-jan-2017: Changed by Gerrit Mantel
- Latin-1 character set is used
TAGS
<program>
<description>Write text variable to file</description>
<generic>1</generic>
<author>Gerrit Mantel</author>
<created>2017-01-25</created>
<lastmodified>2017-01-31</lastmodified>
</program>
*/ DECLARE @objtoken INT
EXEC sp_OACreate 'ADODB.Stream', @objtoken OUTPUT;
EXEC sp_OASetProperty @objtoken, 'Type', 2;
EXEC sp_OASetProperty @objtoken, 'ContentType', 'text/plain'
EXEC sp_OASetProperty @objtoken, 'Encoding', 'quoted-printable'
EXEC sp_OASetProperty @objtoken, 'Charset', 'iso-8859-1'
EXEC sp_OAMethod @objtoken, 'Open';
EXEC sp_OAMethod @objtoken, 'WriteText', NULL, @text;
EXEC sp_OAMethod @objtoken, 'SaveToFile', NULL, @filename, 2;
EXEC sp_OAMethod @objtoken, 'Close';
EXEC sp_OADestroy @objtoken;
END
GO
CREATE PROCEDURE [dbo].[prc_script_tables_multi] (
@dbname NVARCHAR(128) = '',
@path VARCHAR(265) = '',
@includeifnotexists BIT = 0)
AS
BEGIN
/*
SQLServer Stored Procedure
PURPOSE
Script all tables for a given database to individual script files on a given path.
Parameters:
@dbname NVARCHAR(128), default '', Database name
@path VARCHAR(265), default '', Path to dump scripts to
@includeifnotexist BIT, default False, Include "IF NOT EXIST {table} BEGIN ... END" logics surrounding CREATE TABLE statement.
Database must be on current server.
Path to dump files to must exist, and you must have read and write permissions.
The script files will be created on the path: @path\@dbname\TABLE
The filenames are in format [{schema}].[{tablename}].sql
Illegal DOS filename characters in tablenames will cause the powershell script to fail:
\ / : * ? " < > |
The powershell script is based on this blog thread:
https://blogs.msdn.microsoft.com/buckwoody/2009/07/02/powershell-and-sql-server-script-all-tables/
Documentation of the Microsoft.SqlServer.Management.Smo ScriptingOptions Class
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.scriptingoptions.aspx
EXAMPLES
EXEC dbo.prc_script_tables_multi @dbname='PROG', @path='C:\Data\Prog';
EXEC dbo.prc_script_tables_multi @dbname='PROG', @path='C:\Data\Prog', @includeifnotexists=1;
HISTORY
03-oct-2017: Created by Gerrit Mantel
USED OBJECTS
- dbo.fun_FolderExist (User Defined-Function in local database).
- dbo.fun_FileExist (User Defined-Function in local database).
- dbo.prc_save_text_to_file (Stored procedure in local database)
SQLSERVER CONFIGURATION
- OLE Automation has to be enabled.
- xp_cmdshell has to be enabled
TAGS
<program>
<description>Script all tables for a given database to individual script files on a given path</description>
<generic>0</generic>
<author>Gerrit Mantel</author>
<created>2017-10-03</created>
<lastmodified>2017-10-03</lastmodified>
</program>
*/ SET NOCOUNT ON
DECLARE @body NVARCHAR(MAX)
DECLARE @cmd NVARCHAR(4000)
DECLARE @dump_folder VARCHAR(265)
DECLARE @dump_file VARCHAR(265)
DECLARE @message VARCHAR(512)
DECLARE @srvname NVARCHAR(128)
SET @srvname = @@SERVERNAME;
-- Check @dbname
SET @dbname = ISNULL( @dbname,'');
IF @dbname = ''
BEGIN
SET @message = 'ERROR - Parameter @dbname is not specified';
RAISERROR(@message, 16, 1);
RETURN 1
END
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE [name] = @dbname)
BEGIN
SET @message = 'ERROR - Database does not exist: ' + @dbname;
RAISERROR(@message, 16, 1);
RETURN 1
END
-- Check @path
SET @path = ISNULL(@path,'');
IF @path = ''
BEGIN
SET @message = 'ERROR - Parameter @path is not specified';
RAISERROR(@message, 16, 1);
RETURN 1
END
IF RIGHT(@path,1) = '\' SET @path = LEFT(@path,LEN(@path)-1);
IF dbo.fun_FolderExist(@path) = 0
BEGIN
SET @message = 'ERROR - Path does not exist: '+ @path
RAISERROR(@message, 16, 1);
RETURN 1
END
SET @dump_folder = @path + '\' + @dbname + '\TABLE';
-- Check dump_folder
IF dbo.fun_FolderExist(@dump_folder) = 0
BEGIN
-- Folder does not exist, so make directory
SET @cmd = N'mkdir "'+@dump_folder+'"'
EXEC master..xp_cmdshell @cmd, NO_OUTPUT;
END
IF dbo.fun_FolderExist(@dump_folder) = 0
BEGIN
SET @message = 'ERROR - Folder can not be created: '+ @dump_folder
RAISERROR(@message, 16, 1);
RETURN 1
END
SET @body = N'';
SET @body = @body + N'param(
[string]$server,
[string]$database,
[string]$path
)
Import-Module sqlps -DisableNameChecking
$s = New-Object Microsoft.SqlServer.Management.Smo.Server("$server")
$d = $s.Databases["$database"]
$scripter = new-object Microsoft.SqlServer.Management.Smo.Scripter($s)
$scripter.Options.ScriptBatchTerminator = $True
$scripter.Options.ToFileOnly = $True
$scripter.Options.Permissions = $True
$scripter.Options.DriAll = $True
$scripter.Options.Triggers = $True
$scripter.Options.ClusteredIndexes = $True
$scripter.Options.Indexes = $True
$scripter.Options.XmlIndexes = $True
$scripter.Options.NoCollation = $True
$scripter.Options.IncludeHeaders = $True
$scripter.Options.IncludeDatabaseContext = $True
$scripter.Options.IncludeIfNotExists = '+ CASE @includeifnotexists WHEN 1 THEN '$True' ELSE '$False' END + '
$scripter.Options.AnsiFile = $True
foreach($t in $d.Tables) {
$scripter.Options.FileName = "$path\$t.sql"
$scripter.Script($t)
}
"Done"
';
-- Create Powershell script
SET @dump_file = @dump_folder+'\tmp.ps1';
EXEC [dbo].[prc_save_text_to_file] @body, @dump_file;
IF dbo.fun_FileExist(@dump_file) = 0
BEGIN
SET @message = 'ERROR - File can not be created: '+ @dump_file
RAISERROR(@message, 16, 1);
RETURN 1
END
-- Execute Powershell script
SET @cmd = 'powershell.exe -ExecutionPolicy Unrestricted -command "& '+@dump_folder+'\tmp.ps1 -server '''+@srvname+''' -database '''+@dbname+''' -path '''+@dump_folder+'''"'
EXEC master..xp_cmdshell @cmd;
-- Delete Powershell script
SET @cmd = N'del /F "'+@dump_folder+'\tmp.ps1"';
EXEC master..xp_cmdshell @cmd, NO_OUTPUT;
END
GO
CREATE PROCEDURE [dbo].[prc_script_tables_one] (
@dbname NVARCHAR(128) = '',
@path VARCHAR(265) = '',
@includeifnotexists BIT = 0)
AS
BEGIN
/*
SQLServer Stored Procedure
PURPOSE
Script all tables for a given database to one script file on a given path.
Parameters:
@dbname NVARCHAR(128), default '', Database name
@path VARCHAR(265), default '', Path to dump scripts to
@includeifnotexist BIT, default False, Include "IF NOT EXIST {table} BEGIN ... END" logics surrounding CREATE TABLE statement.
Database must be on current server.
Path to dump file to must exist, and you must have read and write permissions.
The script file that will be created is: @path\@dbname$TABLE.sql
The powershell script is based on this blog thread:
https://blogs.msdn.microsoft.com/buckwoody/2009/07/02/powershell-and-sql-server-script-all-tables/
Documentation of the Microsoft.SqlServer.Management.Smo ScriptingOptions Class
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.scriptingoptions.aspx
EXAMPLES
EXEC dbo.prc_script_tables_one @dbname='PROG', @path='C:\Data\Prog';
EXEC dbo.prc_script_tables_one @dbname='PROG', @path='C:\Data\Prog', @includeifnotexists=1;
HISTORY
03-oct-2017: Created by Gerrit Mantel
USED OBJECTS
- dbo.fun_FolderExist (User Defined-Function in local database).
- dbo.fun_FileExist (User Defined-Function in local database).
- dbo.prc_save_text_to_file (Stored procedure in local database)
SQLSERVER CONFIGURATION
- OLE Automation has to be enabled.
- xp_cmdshell has to be enabled
TAGS
<program>
<description>Script all tables for a given database to one script file on a given path</description>
<generic>0</generic>
<author>Gerrit Mantel</author>
<created>2017-10-03</created>
<lastmodified>2017-10-03</lastmodified>
</program>
*/ SET NOCOUNT ON
DECLARE @body VARCHAR(MAX)
DECLARE @cmd NVARCHAR(4000)
DECLARE @dump_file VARCHAR(265)
DECLARE @message VARCHAR(512)
DECLARE @srvname NVARCHAR(128)
SET @srvname = @@SERVERNAME;
-- Check @dbname
SET @dbname = ISNULL( @dbname,'');
IF @dbname = ''
BEGIN
SET @message = 'ERROR - Parameter @dbname is not specified';
RAISERROR(@message, 16, 1);
RETURN 1
END
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE [name] = @dbname)
BEGIN
SET @message = 'ERROR - Database does not exist: ' + @dbname;
RAISERROR(@message, 16, 1);
RETURN 1
END
-- Check @path
SET @path = ISNULL(@path,'');
IF @path = ''
BEGIN
SET @message = 'ERROR - Parameter @path is not specified';
RAISERROR(@message, 16, 1);
RETURN 1
END
IF RIGHT(@path,1) = '\' SET @path = LEFT(@path,LEN(@path)-1);
IF dbo.fun_FolderExist(@path) = 0
BEGIN
SET @message = 'ERROR - Path does not exist: '+ @path
RAISERROR(@message, 16, 1);
RETURN 1
END
SET @body = '';
SET @body = @body + 'param(
[string]$server,
[string]$database,
[string]$filename
)
Import-Module sqlps -DisableNameChecking
$s = New-Object Microsoft.SqlServer.Management.Smo.Server("$server")
$d = $s.Databases["$database"]
$scripter = new-object Microsoft.SqlServer.Management.Smo.Scripter($s)
$scripter.Options.ScriptBatchTerminator = $True
$scripter.Options.ToFileOnly = $True
$scripter.Options.Permissions = $True
$scripter.Options.DriAll = $True
$scripter.Options.Triggers = $True
$scripter.Options.ClusteredIndexes = $True
$scripter.Options.Indexes = $True
$scripter.Options.XmlIndexes = $True
$scripter.Options.NoCollation = $True
$scripter.Options.IncludeIfNotExists = '+ CASE @includeifnotexists WHEN 1 THEN '$True' ELSE '$False' END + '
$scripter.Options.FileName = "$filename"
$scripter.Options.AppendToFile = $True
$scripter.Options.AnsiFile = $True
foreach($t in $d.Tables) {
$scripter.Script($t)
}
"Done"
';
-- Create Powershell script
SET @dump_file = @path+'\tmp.ps1';
EXEC [dbo].[prc_save_text_to_file] @body, @dump_file;
IF dbo.fun_FileExist(@dump_file) = 0
BEGIN
SET @message = 'ERROR - File can not be created: '+ @dump_file
RAISERROR(@message, 16, 1);
RETURN 1
END
-- Create script header
SET @body = 'USE ['+@dbname+']
GO
/****** Objects: TABLE Script Date: '+CONVERT(VARCHAR,GETDATE(),121)+' ******/';
SET @dump_file = @path+'\'+ @dbname+'$TABLE.sql';
EXEC [dbo].[prc_save_text_to_file] @body, @dump_file;
IF dbo.fun_FileExist(@dump_file) = 0
BEGIN
SET @message = 'ERROR - File can not be created: '+ @dump_file
RAISERROR(@message, 16, 1);
RETURN 1
END
-- Execute Powershell script, append to script header
SET @cmd = 'powershell.exe -ExecutionPolicy Unrestricted -command "& '+@path+'\tmp.ps1 -server '''+@srvname+''' -database '''+@dbname+''' -filename '''+@dump_file+'''"'
EXEC master..xp_cmdshell @cmd;
-- Delete Powershell script
SET @cmd = N'del /F "'+@path+'\tmp.ps1"';
EXEC master..xp_cmdshell @cmd, NO_OUTPUT;
END
GO