|

Introduction
Have you ever had to deploy a SQL Server database to a customer? If you have, then you will know that it is certainly not as simple as deploying an application that uses an MS Access database.
With SQL Server databases, you have 3 deployment options that I know of:
- Distribute your .mdf and .ldf files to your customer and attach the database to their SQL Server instance using the system stored procedure
sp_attach_db (or sp_attach_single_file_db). The downside is that the SQL Server must reside on the same machine as the setup application, which is not always the case.
- Use Enterprise Manager to generate your database scripts and BCP to export all of your data to files and import them back in during your setup process.
- Script out your entire database including SQL
Insert statements for importing data into the database.
With options 2 and 3, you can deploy a SQL Server database locally or remotely. This article focuses on option number 3.
Background
There are a number of commercial programs that will script out an entire SQL Server database for you, but due to current financial reasons, I couldn't afford to buy one and so I had to write my own program which only took a few days.
The source code for this article uses the SQLDMO library extensively to interrogate a SQL Server database. SQLDMO is a COM library and is installed with SQL Server 7/2000. (Note: the code for this article will only work for SQL Server 2000 databases).
Using the code
(See figure 1 above)
- When you run the project, enter the connection information for the database you would like to generate scripts for.
- Enter an existing directory for the output. A subdirectory for the database will be placed in the output directory. Underneath the database folder, there is another folder which is used to store all of the
BLOB values as .txt files for Text columns, or .dat files for Image columns.
- If you do not want to generate SQL
Insert scripts for the data in the selected database, then clear this option.
- Press the [Generate] button to start the process. A progress screen will be displayed. Press the [Cancel] button at any time to cancel the process.
- After the generation process has finished, browse to the database folder in the output directory to see a list of files:
| osql.exe |
SQL utility to send batch statements to a SQL Server instance |
| textcopy.exe |
Unsupported SQL utility used to copy 'text' and 'image' values into a SQL Server database |
| createdatabase.sql |
Script to create the database |
| buildobjects.sql |
Script to build all of the objects in the database |
| populatedata.sql |
Script containing SQL Insert statements to populate the database with data |
| importblobvalues.bat |
Batch file to import the blob values into the database.
Parameters required are server name, database, username, password, authentication method. |
| setup.bat |
Batch file to invoke the createobject.sql, buildobjects.sql and populatedata.sql scripts. This batch file is generic to any database. Ability to invoke osql using either Windows Authentication or SQL Server Authentication.
Parameters required are server name, database, username, password, authentication method. |
| install.bat |
Batch file to test the installation.
Normally, your Setup Project would invoke the setup.bat and importblobvalues.bat files directly passing the appropriate values gathered from a custom user interface. |
Before you test the installation:
Please follow steps 6 and 7 carefully to avoid dropping the original database!!
- Open createdatabase.sql in Notepad and change all occurrences (3) of the original database name to something different.
- Open install.bat and change the database name to that chosen in step 6 above.
- To install the database, double-click on install.bat.
Points of Interest
Scripting out Dependent objects first
Even if you use SQL Server Enterprise Manager to script out all of the objects in your database, you will still be left to sort out the order in which objects should be created, as some tables/views/functions and stored procedures may depend on others. This process can be time consuming and tedious.
However, in the article code, the EnumDependencies method was called for each of the objects that may potentially have dependencies and the dependent objects are scripted out first. This should eliminate receiving error messages when the scripts run. Circular references in tables when both tables have foreign keys to the other table would still generate errors though.
Generating a batch file to import BLOB values into a database
When I first started out, I included all BLOB values in the actual INSERT statements. However, when I ran the scripts they produced errors, so I assumed there was a length limit for an INSERT statement.
After a bit of browsing on groups.google.com, I learnt that SQL Server already had sample code to import BLOB values, installed in the C:\Program Files\Microsoft SQL Server\MSSQL\Install directory.
The files of interest are: pubimage.bat, pubtext.bat and instpubs.sql.
The example uses TEXTCOPY.EXE to insert 'text' and 'image' values into the pubs database.
pubtext.bat reprinted below: @echo off
if "%1" == "" goto usage
echo.
echo Inserting images into pubs database on server %1
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '1389'" -Falgodata.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '0877'" -Fbinnet.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '9901'" -Fgggg.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '1622'" -F5lakes.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '0736'" -Fnewmoon.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '9999'" -Flucerne.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '1756'" -Framona.gif
textcopy -I -Usa -P%2 -S%1 -Dpubs -Tpub_info -Clogo
-W"where pub_id = '9952'" -Fscootney.gif
echo Image update complete!
echo.
goto done
:usage
echo.
echo Usage: pubimage ServerName [SAPassword]
echo.
:done
It was only after I was successfully able to script out the pubs database that I learnt that TEXTCOPY.EXE cannot import 'ntext' values. I was very disheartened when I realized this and I still know of no good way to import 'ntext' data into a database. BCP needs format files and file length sizes and can only insert data, not update data.
If anyone knows a good way to import 'ntext' data into a SQL Server database, then please let me know so that I can update this article and provide a complete solution for scripting out an entire SQL Server database.
Conclusion
I've been a fan of CodeProject for some time now and this is my very first article. I hope it will help many of you out when it comes to deploying your SQL Server databases. If you have any suggestions for improvements, please let me know.
History
Version 1. Submitted on 14th April 2004.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 97 (Total in Forum: 97) (Refresh) | FirstPrevNext |
|
|
 |
|
|
This looks like a great tool, and just what the doctor ordered. I need a way to dump my database as a text file full of table insert statements, so I can setup some test cases.
The app does everything you say, except generate the INSERT statements! The only text I get inside of the populatedata.sql file is:
SET NOCOUNT ON -- Restricts volume of output to errors and -- messages that use the PRINT function
Okay, so its obvious this tool is working for everyone else. Yes, I have the "Generate Table Insert Statements" checkbox checked (as well as all the other checkboxes). Anybody have any idea what I might be doing wrong? I'm a C# programmer, so VB isn't my forte, but I guess I'll have to dive into the code, and see why I'm not getting the INSERT statements. If anybody has any ideas, that would be great.
Thanks,
Robin
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I knew that as soon as I posted a question, I'd figure it out. 
I have two SQL Servers running on my machine: SQL Server and SQL Server Express. I had it pointed to the one that had no data in it, so of course, no INSERT statements to generate! After I pointed it to the right place, all is well.
Man, this app is friggen sweeet. Thanks for making this available!!! 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi daffrey,
This is a fantastic tool!! Thanks very much for putting a great effort. This tool satisfies lots of of our needs.
I was able generate SQL scripts for most of the SQL objects from SQL 2000 server 
The scripts that I created was from (local) instance of the database. I wanted to connect to other instance of the local database, when I tried giving , in Server Name field, it was able to logon (at least there was no error related to connection) but didn't create the SQL scripts.
Could you please advice me if there is any option of connecting to other instances apart from default instance.
Thanks again for the great tool.
With warm regards, Mani (manikp@anz.com)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I was searching for this kind of tool and found it useful. Great work, kudos to "daffrey"!!
~KNLReddy
nothing
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
I just want to say that this script rocks, it worked like a charm after i compiled it. Thanks Again to the programmer! You rock!!! 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Unfortunately after long use of this tool I've found out that it doesn't copy triggers - it's a disaster for me - I don't even know at which point I've lost them. Be careful about it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi, i want to generate insert statements as you do in this project. But, I'm a newbie and don't understand everything in this code.
Can you help me and tell me only the code to generate insert statements please ? Thanks.
Regards
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I don't typically reply to articles on codeproject... but I had to for this one. Thanks so much. Awesome stuff.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Ran into a limitation with this tool. Any table with a large amount of data (+5000 rows) may throw a Out Of Memory error as the program stores the insert statements in a string. A possible enhancement might be to create a new method that calls the row generate method passing in an open text file and the data row. Then each row is written to the file and the string is disposed of. I am working on a possible fix but just wated to bring this to everyone's attention.
This is a great tool and I have utilized it many times.
Thanks!
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
I have one table that everytime I run the app fills an ntext column with NULL rather than the data that is in the column. It does not have an issue with any other table in this database, there are about 200. Any thoughts on what the issue might be and how to get it working?
Kent
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
I wrote this batch file to run OSQL with either trusted or login/password. This makes it easier than rewriting entire sections of code. It also can run an inline query or a .sql file and output can be put to a file. I also kept track of stderr and stdout for debugging later. A dash means skip a parameter (although you can't skip stderr and stdout in this example, but instead put CON: to skip).
You can call out to this batch file using CALL RunOSQL.bat params...:
SET SERVER=%1 SET DB=%2 SET QUERY=%3 SET INFILE=%4 SET OUTFILE=%5 SET STDOUT=%6 SET STDERR=%7 SET USER=%8 SET PWD=%9
REM @ECHO OFF REM ECHO SERVER=%SERVER% REM ECHO DB=%DB% REM ECHO QUERY=%QUERY% REM IF /I "%QUERY%" EQU "-" ( REM ECHO INFILE=%INFILE% REM ECHO OUTFILE=%OUTFILE% REM ) ELSE ( REM ECHO No Infile REM ) REM ECHO STDOUT=%STDOUT% REM ECHO STDERR=%STDERR% REM IF /I "%USER%" EQU "-" ( REM ECHO Trusted Connection REM ) ELSE ( REM ECHO USER=%USER% REM ECHO PASSWORD=%PWD% REM ) REM @ECHO ON
REM Run OSQL with the appropriate options: IF /I "%QUERY%" EQU "-" ( IF /I "%USER%" EQU "-" ( osql -S %SERVER% -E -d %DB% -i %INFILE% -o %OUTFILE% >> %STDOUT% 2>> %STDERR% ) ELSE ( osql -S %SERVER% -U %USER% -P %PWD% -d %DB% -i %INFILE% -o %OUTFILE% >> %STDOUT% 2>> %STDERR% ) ) ELSE ( IF /I "%USER%" EQU "-" ( osql -S %SERVER% -E -d %DB% -Q %QUERY% >> %STDOUT% 2>> %STDERR% ) ELSE ( osql -S %SERVER% -U %USER% -P %PWD% -d %DB% -Q %QUERY% >> %STDOUT% 2>> %STDERR% ) )
Henry Lafleur
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Hi there
there's a problem with generating insert statements for table with money data type.
Decimal separator is comma instead of perios, and the values isn't quoted, so INSERT understands it as a 2 values
eg.
INSERT INTO [Courses] ([CourseID],[Name], [CostPerPerson]) VALUES (352, 'ACCA course', 3983,3333 )
the CostPerPerson value (3983,3333) gets interpreted as 2 seperate values and hence the error.
Maybe the program formats those values as strings using server default language instead setting it to some fixed value.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
For everybody having problems with wrong toString conversion of values (bad DateTime format, bad decimal separator format in decimal, float, money types etc.)
Just change the GetValueForTableInsertStatement function code in frmMain.vb and rebuild.
You can see that it usually depends on toString() function of VB.
In case of decimal separator (comma) confilicting with commas in INSERT statement I've added .Replace(",", ".") to: Return Value.ToString().Replace(",", ".")
(line 1464)
Private Function GetValueForTableInsertStatement(ByVal DataTypeName As String, ByVal Value As Object) As String Dim Temp As String Dim dtValue As Date
If Value Is System.DBNull.Value Then Return "NULL"
Select Case DataTypeName.ToLower
Case "int", "decimal", "real", "bigint", "smallint", "tinyint", "float", "money", "numeric", "real", "smallmoney", "varbinary", "binary" Return Value.ToString().Replace(",", ".") ' patch by amiran, original version didn't have .Replace...
Case "nvarchar", "varchar", "char", "nchar", "uniqueidentifier" Return "'" & Value.ToString.Replace("'", "''") & "'"
Case "ntext" Return "NULL" ' Unfortunately not supported as TextCopy does not work on ntext columns
Case "datetime", "smalldatetime", "timestamp" dtValue = CType(Value, Date) ' Convert to universal datetime format (will work on all databases in all countries) Return "'" & dtValue.ToString("yyyy/MM/dd hh:mm:ss tt") & "'"
Case "bit" Temp = Value.ToString() Temp = Temp.Replace("True", "1") Temp = Temp.Replace("False", "0") Return Temp
Case Else ' "sql_variant" columns should be catered for as the underlying physical datatype should be passed to this method Return "NOTSUPPORTED"
End Select
End Function
Amiran
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
We were just debating on the best method to accomplish all this and were gnashing our teeth at the pain involved. A quick Google search and here we are.
Brilliant.
cheers, Chris Maunder CodeProject.com : C++ MVP
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I have been using mySQL for quite some time and thought that the built in feature for generating an entire database including data into sql text would be pretty standard across any major database... obviously not. Want to say thanks for doing a damn good job of doing the work Microsoft should have done.
shannon deminick
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
If I try to script a dateTime cell having the value of 17:00 hours the scripted value is 05:00 hours (which is 12 hours earlier)
Or maybe it is because I try to script an sql2005 db? Or does it have anything to do with regional settings?
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
Hi, great tool, have been trialling it on a new project, with developers at different locations, and it looks great.
One question, is it possible now, or have you given any thought to a command line interface to the tool.
That way the database can be fully scripted as part of the build.
I know this would not be a great process for control of eventual deployment, but in the early stages of dev, with many developers at different locations, this would be a great feature.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|