Monday, June 22, 2009

Export/import relational data across SQL Servers

The XportXML utility, will help you copy relational data (a bunch of related tables) to another SQL Server. There is no rocket science behind the utility as such. It automates many mundane tasks like writing the query to export the data in hierarchical order, and creating XSD schema. This is my first contribution to SQLServerCentral.com, which I rely upon a great deal to learn and improve my skills. Of course, the utility is also posted on my personal blog, which is a collection of my rants and creativity (sometimes).

The script was originally developed in VBA using MS Access. I finally managed to convert it to VB Script(not as easy as I thought). Please make sure that your system can run VB Scripts.

Download Script


Requirements

The script uses SQL DMO to generate export scripts, and SQL Bulk Loader to import data.

How to use XportXML

cscript XportXML.vbs "specification file"


Example:


cscript XportXML.vbs "c:\temp\myspecs.txt"


What happens next

The script creates three files.

  1. export_data.bat
    Run this file to export data in XML format. The data file is created as exported_data.xml in the file location specified in the specification file.

  2. exported_data.xsd
    XSD schema of the exported xml file.

  3. import_data.vbs
    Run this file on the target system to import the data. The XML and XSD files are required for import.


Specification File

Specification file provides instruction to the XportXML about what you want to do. The specification file is a simple text file which can be created using Notepad.

1st Line: Connection information of the source system
2nd Line: Connection information for the target system
3rd Line: Export/Import options
4th line onward: Each line must contain one entry per table to be exported.


Note: A line may contain several parameters, separated by comma, and optionally delimited by double quotes, if necessary. A semicolon in the first column makes it a comment and is not counted toward the line count. A bracket around the parameter indicates, optional item.

1st Line: Connection information for the source database.

[<Src SQL Server User>],[<Src SQL Server Password>],<Src SQL Server>,<Src Source database>,<Src Windows Authentication>

<Src SQL Server User> : If you are using sql server authentication then supply the user name.
<Src SQL Server Password> : If you are using sql server authentication then supply the password.
<Src SQL Server> : Source sql server.
<Src Source database> : Source database name
<Src Windows Authentication> : Y or N.


Examples:
1. Windows authentication, extract from AdventureWorks database from localserver.
,,ASUSAK\SQLEXPRESS,adventureworks,Y

2. SQL Authentication, extract from AdventureWorks database from localserver.
sa,mypassword,ASUSAK\SQLEXPRESS,adventureworks,N


2nd Line: Connection information for the target database.

You can always change this information in the generated scripts later.

[<Tgt SQL Server User>],[<Tgt SQL Server Password>],<Tgt SQL Server>,<TGt Source database>,<Tgt Windows Authentication>

<Tgt SQL Server User> : If you are using sql server authentication then supply the user name.
<Tgt SQL Server Password> : If you are using sql server authentication then supply the password.
<Tgt SQL Server> : Source sql server.
<Tgt Source database> : Source database name
<Tgt Windows Authentication> : Y or N.


Examples:
1. Windows authentication, extract from AdventureWorks database from localserver.
,,ASUSAK\SQLEXPRESS,adventureworks,Y

2. SQL Authentication, extract from AdventureWorks database from localserver.
sa,mypassword,ASUSAK\SQLEXPRESS,adventureworks,N


3rd Line: Export options.

[<Files location>],[<Drop tgt tables>],[<Create tgt tables>],[<Keep identity column values>]

<Files location> : Path where all scripts will be created. Default c:\

<Drop tgt tables>: Y or N. If Y, target tables will be dropped before import. Default N.

<Create tgt tables>: Y or N. If Y, target tables will be created if they do not exist. Default Y.

<Keep identity column values>: Y or N. If Y, if the PK is an identity column, the source values will be retained. If N, new values will be generated for the parent and child tables. Default N.


4th line onward: Exported table information

<Level>,<Src table name>,[<Tgt table name>],<[<Where clause>]

<Level> : This field establishes the hierarchy of the exported XML data. The very first record must contain a value 1 for the root table. The child tables will contain 2, 3 etc.

<Src table name> : You can use [<owner>].[<table name>], [<table name>], <owner>.<tablename>, or simply <tablename> formats. If owner is not specified, dbo is assumed.

<Tgt table name> : You can use [<owner>].[<table name>], [<table name>], <owner>.<tablename>, or simply <tablename> formats. If owner is not specified, dbo is assumed. If this parameter is omitted, then a table with _xs<Src table name> will be used as the target table.

<Where clause> : Use [<table name>].[<column name>]=<Value> format. If this clause is ignored, all rows are selected.


Examples of specification file


Example a:


,,ASUSAK,Adventureworks,Y
,,ASUSAK,Lab1,Y
c:\temp
1Production.ProductCategory
2Production.ProductSubcategory
3Production.Product

In the above example, the hierarchy is established as Category, Subcategory, and Product tables. The data will be exported into dbo._xsProductCategory, dbo._xsProductSubcategory, and dbo._xsProduct tables. The specification file above will bring less rows in the Product table than the source. This is because many products in Adventureworks database are not assigned any ProductSubCategory. Hence, the join between product.ProductSubCategoryId and ProductSubCategory.ProductSubCategoryId fails.


Example b:


,,ASUSAK,Adventureworks,Y
,,ASUSAK,Lab1,Y
c:\temp,N,Y,N
1Production.ProductCategory,user1.cat
2Production.ProductSubcategory,user1.subcat
3Production.Product,user1,prod

In the above example, the hierarchy is established as Category, Subcategory, and Product tables. The data will be exported into user1.cat, user1.subcat, and user1.prod tables. Old tables will not be dropped. New tables will be created if they do not exist. Identity columns will be re-created if the target tables' primary key columns were set up as identity.


Example c:

,,ASUSAK,Adventureworks,Y
,,ASUSAK,Lab1,Y
c:\temp
1Production.ProductCategory,,"[productcategory].name='Bikes'"
2Production.ProductSubcategory
3Production.Product

In the above example, the hierarchy is established as Category, Subcategory, and Product tables. The data will be exported into dbo._xsProductCategory, dbo._xsProductSubcategory, and dbo._xsProduct tables. Only rows with Production.productcategory.names='Bikes' will be exported.


Tip: How to extract tables which do not have any relationship with each other

Create a dummy table with one row. Make this table as the root table (level 1). You can pick any column name(s) in the dummy table. There is no need to create any constraints either. That's it.

,,ASUSAK,Adventureworks,Y
,,ASUSAK,Lab1,Y
c:\temp
1dummy
2production.category
3production.SubCategory
2HumanResources.Department

In the above example, dummy table will be imported as _xsDummy. All rows of Production.Category will be imported as dbo.category. All related rows of production.SubCategory will be imported as dbo.Subcategory. All rows of HumanResources.Department will be imported as dbo.Department.


Gotchas

  1. I did not have time to put any error checking. If the script bombs, you will need to figure out what went wrong. Most of the time, it is due to an error in the specification file.
  2. The import may still fail because your lowest level child may still have links to parent(s), which you are not importing.

  3. The parent child relationship is picked up from the foreign key constraint in the database. If the constraint does not exist, you will get a Cartesian product for the child table.
  4. If the data being brought is setup as relational in the specification file then only related rows will be brought over.
  5. If the target tables are created automatically by BulkImport, the order of columns may change a little. Unfortunately, there is no way to correct this behavior. If the tables have been created before hand then this issue is irrelevant.
  6. The XSD schema generated by this utility, and the XML generated by bcp export are not indented properly. I recommend a wonderful tool, Free XML Editor from FirstObject.com. Load the file in the editor and press F8, and you will see wonderfully indented XML file.

Final Note

Folks, there is a lot to be desired in this utility. Please give me constructive suggestions to make this utility better.
I have already added the following to my next version:

  1. Re-adjust the foreign keys in imported items where parents were not included in the export. Of course, this is not as easy as it sounds. I am looking for some input from you.
  2. Add some error handling. It is kind of low in my priority list, but it must be done.

Wednesday, May 6, 2009

Dell guy

I love to interact with people because I find interesting people in all facets of my life. Today, I met a very interesting technician from Dell. He came over to my house to fix a broken laptop. My dogs, as usual, first gave him the customary welcome bark then tried to hump his leg. It did not bother him a bit. I guess, he was so used to it. He was a very friendly guy. He told me, he had been to a house recently, where this lady had twelve cats. Twelve cats! Wow! He was nervous because one of the cats was on the kitchen cabinet, watching him. "Yep, let me see as soon as you have that mother board opened with 100 little screws on the table, I am gonna jump on it". He was nervous. Luckily the cat did not jump. I made a comment, may the lady was lonely and needed twelve cats for company. "This is not the kinda of question you ask from customers", told the technician in his light Russian accent. I understood immediately.

He told me another interesting story. He went to repair a mother board at an old lady's house. After he disassembled the mother board, there were about fifty odd screws on the table. The old lady somehow developed a non-confidence in him to repair the computer. She called her daughter, described her reservations, and asked her to talk to the technician. The daughter told him if he can answer one question, he can continue repairing the laptop. She asked, "What happens if after assembling the laptop, one screw is left out"? The technician replied, "Well, it has never happened, but it is possible. Now, if that happens, I will eat the screw". The daughter said, "I have one more question. How many screws do you eat every day"? I have no doubt in my mind that the story is true because I have tried to repair mother boards myself, and they put way too many screws.

He also told me he worked in Adis Ababa, Ethopia (yes). Apparently, both the gals and guys go to bathroom on the streets, if they have to. Now, I am not foreign to the concept of going to bathroom on the streets, but never thought that the gals did it.

Anyway, Mr. Dell Guy, I think you have a cool job. Write a book some day!

Sunday, May 3, 2009

A tribute to Danny Gans

I had not even heard of Danny Gans before I saw him on CNN's Larry King Live in February 2009. My son and I were watching the program and within minutes we were glued to the TV to find his next act on Larry's show. Danny did a variety entertainment show in Vegas. His talent was to do impressions of over 200 celebrities.

http://www.cnn.com/2009/SHOWBIZ/05/01/obit.gans/index.html?iref=newssearch#cnnSTCVideo

I knew nothing about him before yet I found him to be a great human being who simply enjoyed what he did. I noticed a lot of humility in him. I made a mental note to add an item in the list of things before I die. It was, to watch Danny Gans live in Vegas. Yesterday, when I read in the papers about his sudden demise, I could not believe it. I woke my son up and told him about the news as well.

Danny, I am sure a whole lot of people will miss you, I know I will. Make heavens laugh, will ya!!