![]() |
|
|
By: Armando Prato | Read Comments (6) | Print Armando has over 24 years of industry experience and has been working with SQL Server since version 6.5. Related Tips: 1 | 2 | 3 | More |
|
Problem
My company has a number of SQL installation scripts that build a fresh copy of our database. Each script relates to a specific SQL task. One script builds the database, another builds the tables, etc. I call SQLCMD repeatedly to execute each script. Is it possible to concatenate these scripts together and execute them with a single call to SQLCMD?
Solution
Yes it is. SQLCMD offers the :r command. When :r is encountered in a SQL script, it essentially tells the SQLCMD utility to include the file referenced into the calling script. This can afford you the opportunity to break up a single script into multiple scripts that represent functional areas of the database or to replace multiple SQLCMD calls with a single call to a main SQL file. Furthermore, using the :r command to execute multiple scripts in a single batch allows you define a single set of variables which can be seen by all the included scripts (provided there is no intervening GO terminator). SQLCMD was introduced in SQL Server 2005 and is the replacement for osql which Microsoft will be deprecating in a future release. If you're not familiar with SQLCMD, it is a command line utility that can be used to execute T-SQL commands and scripts from the operating system.
NOTE: You can download the sample files via the attached .zip file which you can unzip and use to execute the sample code that will be presented in this tip.
In the forthcoming example, I'll create 5 .sql files representing functional areas of a sample database called MSSQLTIPS. The first script is called CREATE_DB.sql and creates a database on your SQL 2005 Server called MSSQLTIPS. This script then includes 4 scripts (using the :r command) to perform table creation, table inserts, index creation, and stored procedure creation. A .bat file is created to execute SQLCMD from the Windows operating system in order to create a fresh database.
I first create a sub-folder under my C: drive called C:\Scripts. I store the following SQL scripts in this folder.
| Script code to create tables |
/* SCRIPT: CREATE_TABLES.sql */ PRINT 'CREATING TABLES ' GO IF OBJECT_ID('EMPLOYEE') IS NOT NULL DROP TABLE DBO.EMPLOYEE GO CREATE TABLE DBO.EMPLOYEE ( EMPLOYEEID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, FIRSTNAME VARCHAR(50), LASTNAME VARCHAR(50) ) GO IF OBJECT_ID('TIMECARD') IS NOT NULL DROP TABLE DBO.TIMECARD GO CREATE TABLE DBO.TIMECARD ( TIMECARDID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, EMPLOYEEID INT NOT NULL, HOURSWORKED TINYINT NOT NULL, HOURLYRATE MONEY NOT NULL, DATEWORKED DATETIME NOT NULL ) GO DECLARE @TOTAL_TABLES INT SET @TOTAL_TABLES = 2 |
| Script code to insert data |
/* SCRIPT: TABLE_INSERTS.sql */ PRINT 'TOTAL TABLES CREATED = ' + CAST(@TOTAL_TABLES AS VARCHAR) GO PRINT 'INSERTING DATA INTO EMPLOYEE' GO INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME) SELECT 'JOHN', 'DOE' GO INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME) SELECT 'JANE', 'DOE' GO INSERT INTO DBO.EMPLOYEE (FIRSTNAME, LASTNAME) SELECT 'JEFF', 'DOE' GO |
| Script code to create indexes |
/* SCRIPT: CREATE_INDEXES.sql */ PRINT 'CREATING INDEXES' GO IF NOT EXISTS (SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IX_EMPLOYEE_LASTNAME') CREATE INDEX IX_EMPLOYEE_LASTNAME ON DBO.EMPLOYEE(LASTNAME, FIRSTNAME) GO IF NOT EXISTS (SELECT 1 FROM SYS.INDEXES WHERE NAME = 'IX_TIMECARD_EMPLOYEEID') CREATE INDEX IX_TIMECARD_EMPLOYEEID ON DBO.TIMECARD(EMPLOYEEID) GO |
| Script code to create procedures |
/* SCRIPT: CREATE_PROCEDURES.sql */ PRINT 'CREATING PROCEDUREs' GO IF OBJECT_ID('GET_EMPLOYEE_TIMECARDS') IS NOT NULL DROP PROCEDURE DBO.GET_EMPLOYEE_TIMECARDS GO CREATE PROCEDURE DBO.GET_EMPLOYEE_TIMECARDS @EMPLOYEEID INT AS SET NOCOUNT ON SELECT * FROM DBO.EMPLOYEE E JOIN DBO.TIMECARD T ON E.EMPLOYEEID = T.EMPLOYEEID WHERE E.EMPLOYEEID = @EMPLOYEEID ORDER BY DATEWORKED GO |
| Script code to create the new database and objects |
/* SCRIPT: CREATE_DB.sql */ /* BUILD A DATABASE */ -- This is the main caller for each script SET NOCOUNT ON GO PRINT 'CREATING DATABASE' IF EXISTS (SELECT 1 FROM SYS.DATABASES WHERE NAME = 'MSSQLTIPS') DROP DATABASE MSSQLTIPS GO CREATE DATABASE MSSQLTIPS GO :On Error exit :r c:\Scripts\CREATE_TABLES.sql :r c:\Scripts\TABLE_INSERTS.sql :r c:\Scripts\CREATE_INDEXES.sql :r c:\Scripts\CREATE_PROCEDURES.sql PRINT 'DATABASE CREATE IS COMPLETE' GO |
In the root C:\ folder, I create a file called create_db.bat which I use to create the database with all objects
SQLCMD -E -dmaster -ic:\Scripts\create_db.sql PAUSE |
Double clicking the .bat file, I see that each script processed and that the database created successfully.
The SQLCMD utility offers a wealth of commands that can used to modify the .bat file to further control and refine output and error behavior.
Next Steps
| Share: | Share | Tweet |
|
![]() |
![]() |
Connect with MSSQLTips.com |
| Wednesday, May 27, 2009 - 11:35:19 AM - Roberto12cr | Read The Tip |
|
And what happen if there are an error in the script #5, all the previous script already were executed.
There are any way to do this in a transaction? |
|
| Thursday, January 27, 2011 - 9:39:28 AM - tskelley | Read The Tip |
|
My same concern. Our scripts will sometimes have errors due to dependencies, etc. The errors are not always critical and require rollback; however, we would like to make sure the error condition is reported and the output is preserved, just in case... Maybe this could be the next part of this article. :)
|
|
| Wednesday, May 11, 2011 - 2:07:00 PM - Joffre | Read The Tip |
|
I use the script below to create a new database: sqlcmd -S srv-tsbd\sql2k -i D:\Scripts\create_db_2k.sql -o D:\Scripts\Logs\LOG_create_db_2k.txt Is it right? It creates... Now I'm trying to create the tables with some scripts that I have. The scripts for creating tables are in different places, and they CAN'T be moved. For example: The CREATE TABLE a is on Folder D:\Scripts\Create\A The CREATE TABLE b is on Folder D:\Scripts\Create\B
How do I do?
|
|
| Tuesday, March 13, 2012 - 4:10:59 AM - bob | Read The Tip |
|
You could try a small utility
https://scriptzrunner.codeplex.com/ |
|
| Friday, March 16, 2012 - 3:48:26 AM - Della | Read The Tip |
| Try these tipsEnable the TCP/IP poocrtol using the Surface Area Configuration Utility Make sure the TCP/IP poocrtol is enabled in the SQL Server Configuration UtilityMake sure the SQL Server browser is started. Note this stepis optional. It is possible to set the SQL Server instance to use a fixed IP address but this isnon-standard for named instancesMake sure SQL Server and SQL Server Browser are exempted by the firewall on the server machine.This is done by putting sqlservr.exe and sqlbrowser.exe as an exception in thewindows firewall.Note: In order to get things to work. You might need to completely reboot theserver machine after making the changes. There have been reports (thanks P.C.) that starting and stopping theSQL Server and Browser software is not enough. | |
| Wednesday, April 25, 2012 - 8:22:06 AM - Jorge Segarra | Read The Tip |
|
Regarding the concern about rollback. What you could do is include BEGIN/COMMIT TRAN in each script. This will give you rollback granualirity at each piece of the process. You cannot do nested transactions (See Paul Randal's post on the matter: http://www.sqlskills.com/BLOGS/PAUL/post/A-SQL-Server-DBA-myth-a-day-(2630)-nested-transactions-are-real.aspx). This tip was meant as general overview/example of using sqlcmd, not thorough breakdown of its uses, which I think the author did good job of showing. |
|
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |