|

Introduction
If you are using a source control system to manage your project's source code, you have probably wondered if you could do the same with your database. You can! Here's my take at it: ScriptDB4Svn does what its name suggests: it scripts your database for usage in a source control system. Because I use SVN with the TortoiseSVN shell extensions, I've targeted this project to be used with SVN, but you can probably use it with other source control systems.
Please note that the tool relies upon the Scripting tool from Microsoft which was shipped with SQL Server 2000, and will only have been installed on your system if you chose for backward compatibility with SQL Server 7.0 during the installation. If you are missing the tool (scptxfr.exe) it can be found on the SQL Server 2000 installation CD.
The tool was tested on SQL Server 2000 only. I don't know if it works with SQL Server 2005.
What does ScriptDB4Svn do exactly?
The tool scripts Microsoft SQL Server tables, relationships, views, stored procedures, user defined types, defaults, rules, triggers, functions and data into individual .sql files. Those individual files can then be added to your source control system and become available for versioning. The tool can also be used to automatically create a clean database from generated scripts, which can be very useful for integration in any tools like NAnt, MSBuild, CC.net etc.
What are the benefits?
There are numerous benefits; these are just the ones I came up with. If you have any additions, let me know!
- You are aware of other developer’s database changes and they are aware of yours. Your databases will remain in-sync with each other.
- See who added what table, column, trigger, or broke your stored procedure. (‘SVN Blame’ shows what was added/changed when and by whom)
- Create clean databases from generated scripts for easy deployments to test and production environments.
- Add database script execution to continuous integration scripts.
- If you lose anything in your database, you have multiple scripted backups so you can easily restore it.
- Tagging: When releasing a new version of your program, include the exact version of the database and its data within the same SVN Tag / branch!
Working with ScriptDB4Svn - Manual
Put a copy of ScriptDB4SVN.exe and its .config file in the folder where you want your database scripted. Open the .config file and make proper changes to it. The file contains comments that will tell you what the different settings are for.
If you are going to use the tool in your development team, I recommend you to have everyone in your team read this article. I will save you some headaches!
How to manage database changes
- If any project-member makes a change to anything in their version of the database, they simply run the scripting tool to regenerate the scripts, and then commit the changes to the SVN repository.
- Upon executing an SVN Update command, any updated scripts are copied to other team members’ local versions. Once they run the scripting tool again, the database changes are reflected in Windows Explorer by TortoiseSVN. By viewing the TortoiseSVN Diff view of the table/view/whatever, the exact changes made by the developer become visible.
- The other team members make the appropriate changes to their local databases, either by executing the new script, or by making the changes manually in SQL Server.
- Once the tool generates scripts identical to the ones in the repository, the databases are in-sync again!
A paradoxical thing about this approach is that changes made by other developers only become visible after the scripts are regenerated locally. This way, it appears that the remote database changes have been ‘undone’ locally, while in fact the remote changes haven’t been processed (copied) yet. Any –uncommitted– changes a developer has made to their local database, will appear in the same way remote developers’ –unprocessed– changes appear in Windows Explorer.
Handling/resolving data differences
Resolving data conflict can be a pain because of relationships that assure the relational integrity of the data is maintained. If the data in more than one table has changed, simply executing a delete statement or inserting data can cause errors. In these situations it is quite useful to remove those constraints, update the data and then recreate the relationships. When done, the dropped constraints can easily be re-created from the Relationship scripts. Follow these steps to avoid annoyances:
- SVN Revert your version of the data script to the HEAD ('their') revision.
- Open the script in Query Analyzer, connect to the right database
- Execute the script
- If step 3 generated an error, find out what constraint caused the error, above the
DELETE FROM the_current_table line, add: ALTER TABLE table_that_contains_the_constraint DROP CONSTRAINT FK_the_name_of_the_annoying_constraint, now try step 3 again. Repeat this until the script executes without errors.
- Repeat steps 1 to 4 until all data changes have been made.
- Rescript your database. If you dropped any constraints in step 3, recreate them by executing the appropriate relationship scripts (SVN Revert the file, strip the lines for constraints that still exist, execute)
Important note: Watch out for relationships that have CASCADE DELETE's enabled! Deleting data in a source controlled table could then result in the loss of data of other -possibly not source controlled- tables!!
Handling/resolving minor script differences
There are a couple of situations where differences in generated scripts can occur, when they aren’t really different. Here’s how you can resolve them:
- Index/PK names: To resolve a difference in the name of a Primary key or index, in SQL Query Analyzer, execute:
sp_rename 'myname', 'theirname'
- CASE differences in table & column names: execute
sp_rename 'dbo.Table.someColumn', 'SomeColumn'
- CASE differences in
CREATE statements: for some odd reason SQL Server remembers the case of the CREATE statement when it was executed. For any other object than tables, SVN Revert your version of the .sql file to the HEAD revision, open the file in Query Analyzer and execute it.
- COLLATION differences: these can be a real pain. If the developers in a team are using different collation settings in SQL Server, any textual columns like
varchar and text will contain different collations. Make sure to all use the same collation settings! If you aren’t bothered by different collation settings, you can optionally turn “IgnoreCollation” on in the .config file of the tool.
Handling conflicts
Sometimes conflicts can occur in the script files. Usually this is the result of not committing the generated scripts after local database changes have been made. The best way to resolve conflicts is:
- Regenerate your scripts, any conflict files will be removed automatically.
- Now, check the Diff and make any pending changes to your database.
- Regenerate the scripts again and commit your file.
Best practices
Follow these guidelines to prevent yourself from getting into problems.
- Commit local database changes to the SVN repository as soon as possible, but only if any programming code that relies upon the DB change is committed at the same time. If the change can break code other developers are using, provide code that fixes those problems within the same commit.
- Schedule an automatic SVN Update, and the script tool to be executed at least once a day so you will notice committed database changes as soon as possible. 9 AM is a nice time for this: new day, new scripts.
- Process other users’ database changes immediately when you notice them. Waiting to do so will make your life hard.
- Put a copy of the ScriptDB4SVN.exe in the folder that contains the scripts and Add it to the repository. If an updated version becomes available, you can simply overwrite it with the new version. Other developers automatically take over the new version upon SVN Update.
- If you deleted a table/view/anything from your database, don’t remove the corresponding script file! The contents of the script file will automatically be cleared by the tool. This way the deletion will be noticed by other developers. Once -everybody- has deleted the item, the file can be removed from SVN.
History
- October 8, 2006: Original article posted.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 32 (Total in Forum: 32) (Refresh) | FirstPrevNext |
|
|
 |
|
|
We are just about to move from 2000 to 2005. I just found this tool and would be interested in getting familiar with it now and using it in production when we move to 2005. Has anyone tried it with 2005?
Warm regards,
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yes, I tried it in SQL 2005, works just fine from what I can tell, scripts created and appear right! Thanks for the tool, this will be very handy and offer a layer of code protection which we didn't have before.
Becker
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
in file Program.cs function Main line 125 should change
if (tables2Script.Length > 0)
to
if (!string.IsNullOrEmpty(tables2Script))
to prevent program crash if key "ScriptTableData" is absent in the config file.
Peoples should think. Machines shold work.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Has anyone tried to use this tool with SQL Server 2005 ? (I'll have a closer look at it myself as soon as i have the time).
We are looking for a way to store SCADA applications in SVN, so this would be quite handy for us. A few SCADA systems we use (like Siemens WinCC) are based on SQL Server these days, which makes the use of SVN hard since the whole database must be detached, checked in and re-attached with every change, and most of that data is useless anyway.
If anyone has experience with it, i would like to share idease with him/her.
regards, Peter
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Your program deletes all previous *.sql files in all directories (well deletes in the root and blanks in subfolders). This is assuming that everything in the project folder where you run this executeable is owned by the executable. I had created a version update file for migration (surely one of the reasons to have versioned control databases) and this got nuked before I committed it. Doah!
To cope with this I've hard coded a it so it won't delete from a folder called updates now on but it would be cool if you could have an exclusions folder in the config. Just looked and found out it has been nuking my livedata files, my test scripts too... lucky for version control!
Thanks though for creating it. It's been very useful otherwise!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I have a "varbinary(max)" data-type in a table def, and scriptdb4svn is generating the following on an exportdb:
[value] [varbinary] (-1) NULL ,
which is invalid sql  I can't just substitute an actual number in the column def, since anything over 8000 is rejected. SQL Server won't take an actual length > 8000, hence the "max" keyword. "varbinary(max)" means anything well into gigabyte range.
How can I have a varbinary and have scriptdb4svn handle it correctly?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
It appears the SQL scripter from SQL Server 2000 doesn't support the varchar(MAX). I hacked together a fix several months ago. In the Program.cs near the bottom, I added the following lines.
// Trim trailing \n so output of different servers is the same statement = statement.TrimEnd(new char[] {'\n', '\r'});
if (includeOwner && owner.Length > 0) objectname = owner + "." + objectname;
string varbinary = "[varbinary] (-1)";
if (groupName == "Tables" && statement.Contains(varbinary)) statement = statement.Replace(varbinary, "[varbinary] (max)");
string varchar = "[varchar] (-1)";
if (groupName == "Tables" && statement.Contains(varchar)) statement = statement.Replace(varchar, "[varchar] (max)");
string filename = outputPath + "\\" + groupName + "\\" + objectname + ".sql";
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
I have a user-defined function that contains the following in a comment:
/* SCRIPTING NOTE: When generating a SQL script for the database, the script creates this function before some of the objects it depends on. To avoid errrors, move the "CREATE FUNCTION dbo.GETUSERFUNCTIONDEPARTMENTS" before "CREATE VIEW dbo.View1". */
Your script detects the creation of a new view and starts scripting a view that contains an error. How would you update this code to ignore create statements that have been commented out? I believe you need to add something to the regular-expression, but I'm not a RegExpert. Any ideas?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I've found the utility does not like comments in triggers to appear before the "AS". If comments occur before "AS", the comment is included in the object's name.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Some old sql view's are not identified well and makes the code stop processing the database:
The issue is:
Normal view looks like this:
Create View view_name AS Select ...
View can also be declared this way:
Create View view_name(column_name1, column_name2, ...) AS Select ...
Some people prefer to enlist the result column layout in the view declaration section instead of writing the wanted (alias) name in the select statement at the appropriate column/line (example: Select table_name1.column_name1 As col_1)
Now the code is prepared for the simple version only, and breaks on the one which lists the columns
Since I am not really familiar with regex I cannot really make an appropriate regex for the views. (I do not have VS2005 either)
Could you make some modification to detect this declration type as well in the views? Compile a new version or at least give me some hint what to change in the regex and then I will try to get VS2005 and compile it for myself.
Thanks a lot,
Andrew
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
?<Statement>CREATE VIEW (?<Owner>[^\\.\\s]*?\\.)?(?<Name>.*?)\\s+AS\\s+.*?)\\s+GO\\s
The RegEx for VIEWS above does not exclude statement permissions like these:
GRANT CREATE TABLE , CREATE VIEW , CREATE PROCEDURE , DUMP DATABASE , CREATE DEFAULT , DUMP TRANSACTION , CREATE RULE TO [SlydellB] GO
I don't have any experience with RegEx. How to fix that?
Best Wishes, Robin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
It's useful for development tool, but I can't work with SQL Server 2005 I can't find scptxfr.exe. What should I do? Do you know other tools use IDE SQL Server with SVN?
Chhers, Samnang
|
| Sign In·View Thread·PermaLink | 1.50/5 (2 votes) |
|
|
|
 |
|
|
Hi,
After trying (I am new to C#) and searching the internet, I realized that this project has been implemented using Visual Studio 2005 and possibly with C# version later to 1.1.
That's why I was getting the errors. Changing this utility so that I can compile it with C# version 1.1, I need to change the code (no static class is allowed with versions prio to 2, Container classes are different, etc) which amount to re-writting the utility.
I was just wondering if you have a version of this utility that was implemented using Visual Studio (version prio to 2005 and C# 1.1)?
Regards,
/********************** David nsengiyumva 3, Clarendon Road, Rosebank, 7700 Cape Town ***********************/
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
Hi,
The following line in the 'DataScripter' static class:
List<string> sortColumns = new List<string>();
gives the following error: Invalid expression term 'string'
Any idea what's causing this or how to fix this.
Many thanks
N.B: I am using Visual Studio .Net 2003
/********************** David nsengiyumva 3, Clarendon Road, Rosebank, 7700 Cape Town ***********************/
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This is a C# 2.0 project, will only compile in Visual Studio 2005 and up. If you want to convert the code to 1.1, convert the generic definitions to plain ArrayLists:
this code:
List sortColumns = new List();
becomes:
ArrayList sortColumns = new ArrayList();
There will probably be more issues along the way. If you say you are new to C#, I wouldn't recommend trying to convert the code. Good luck with it anyways!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I've been trying to open the project file using Visual Studio .NET 2003 but I get an error message saying that ScriptDB4SVN.csproj' is not a valid project file and I have checked the file against my other project files and it looks different... Any idea how to fix this??? I tried creating a new project but I don't know the type of project to create... Any help will be appreciated.
Thanks
/********************** David nsengiyumva 3, Clarendon Road, Rosebank, 7700 Cape Town ***********************/
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
This code worked like a champ. I can say we upgraded recently to 2005 and this still works on our database using Scptxfr.exe and .rll files from the sql 2000 server install disk.
I had to make 1 modification to the code to exclude some wierd characters we are using in the tablenames? Just used an "objectname = objectname.Replace()", if anyone else needs to do the same.
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
My database has a table named "User" in it. Unfortunately "User" is are MS SQL Server reserved keyword. I know, naughty me. Unfortunately, this breaks your code at line 55 of the DataScripter.cs file. The line reads:
command.CommandText = string.Format("SELECT * FROM {0} ORDER BY {1}", table, orderBy);
I fixed it by adding brackets around the table reference:
command.CommandText = string.Format("SELECT * FROM [{0}] ORDER BY {1}", table, orderBy);
Other than that, your app is working well. Thanks for the help.
-- Tod Birdsall, MCSD for .Net software blog: http://www.tod1d.net
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Go to www.red-gate.com and download a program called 'SQL Refactor'. This will allow you to rename those pesky objects with reserved keywords as the name... They offer a 30 day trial so there isn't anything to lose - you might even want to buy it. 
I don't work for red-gate, I am a user and I absolutely love it so I thought I would share. hth
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Instead of reverse engineering your database back into scripts and then putting those scripts in PVCS, you should create/checked out the scripts and then updated the database with them. Wow, I'm shocked if people use this process in production environments.
What you propose would be okay for a one time operation if this was never done for some reason (for example you took over from a newly fired consultant).
|
| Sign In·View Thread·PermaLink | 1.27/5 (6 votes) |
|
|
|
 |
|
|
Thanks for your comments.
Unlike PVCS, SVN doesn't use a locking mechanism for files managed. This is one of the great benefits of SVN. In the scenario of database versioning, this literally means you and one or more of your collegues can make changes to the same table at the same time, check in those changes and all have these changes merged back into their local databases seamlessly.
Your suggested solution would work great in a single database server development environment, with all developers working on that one database all at the same time. However, this tool provides a way to have developers independently work at local versions of their databases, and only check in/merge changes back into mainstream development once their changes have been successfully implemented. Just like they would do with their source code files.
Also, this tool is not targeted for use in production environments, it is a development tool for use in development environments.
|
| Sign In·View Thread·PermaLink | 4.33/5 (6 votes) |
|
|
|
 |
|
|
Foreign keys can go unnamed, so the regular expression to separate them from the tables, should be:
"(?\\s(CONSTRAINT \\[[a-z0-1_]*?\\] )?FOREIGN KEY.*?\\(.*?\\) REFERENCES .*?\\(.*?\\)(?:\\s*ON (?:DELETE|UPDATE) CASCADE\\s*)*(?:,)?)"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I use this improved regexp. It can detect foreign keys without CONSTRAINT word (based on before message) and also works with "NOT FOR REPLICATION" clause:
"(?\\s(CONSTRAINT \\[[a-z0-1_]*?\\] )?FOREIGN KEY.*?\\(.*?\\) REFERENCES .*?\\(.*?\\)(?:\\s*ON (?:DELETE|UPDATE) CASCADE\\s*)*(?:\\s*NOT( )*FOR( )*REPLICATION\\s*)*(?:,)?)"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|