How to import a Sql Server Compact Database into Sql Server 2008 PDF Print E-mail
Written by Joris Bijvoets   
Friday, 15 January 2010 06:26

Exporting a database from Sql Server Compact to Sql Server 2008

I'm developing an application, which originally used a Sql Server Compact database.The reason to chose rhis database was it's easy use, fine integration with Visual Basic.Net and the possibility to copy the database with maximum ease.

But during an early test-phase I stumbled onto the field length limitations in this database, as the xml-data which had te be stored was too long. It seemed to me the best solution for this challenge was converting the Sql Server Compact Database to Sql Server 2008.

With confidence I started to search the internet for a freeware tool or script that could do the job for me. After a search of an hour I gave up. I couldn't find what I was looking for. As I can be stubborn I decided to write the tool myself.

Engineering a tool to copy structure from Sql Server Compact to Sql Server 2008

I thought about what the tool had to do. I came up with the following two points:

  1. Examine the structure of the Sql Server Compact Database, and retrieve all data
  2. Create the tables and copy the data to the Sql Server 2008 database

Examine the database structure from a Sql Server Compact Database

In a previous article I wrote about examining the database structure from a Sql Server Compact 3.5 database. This part was the easy part:

  • create and open a connection to the database file
  • Loop through the fields for each table, reading each fieldname and fieldtype
  • Loop through each record for each table, reading each value from each field

Creating the table structure in Sql Server 2008

With the structure found in the first step, it should be possible to create a table in Sql Server 2008. Building a SQL CREATE command, with the right fields and field types, could do the job.

'connSqlCompactDatabase is a SqlCeConnection, defining the connection to the Sql Server Compact Database

'sTable is a string, filled with the Table name to copy

Dim cmd As New SqlCeCommand("Select * from " & sTable, connSqlCompactDatabase)

Dim dr As SqlCeDataReader

Dim flds As String = "" 'Variable to hold the fields of the table

dr = cmd.ExecuteReader 'read complete table

'Sql variable is a string in which the complete CREATE TABLE Sql statement will be build

Dim Sql As String = "Create table " & sTable & "( "


Dim comma As String = "" 'Variable to seperate fields in the query.

For i As Integer = 0 To dr.FieldCount - 1

'All my tables have an Id-field, which is a bigint, defining Identity.

'If you use this code, probably you have to rewrite this part
If dr.GetName(i) = "id" Then
Sql &= comma & dr.GetName(i) & " bigint  IDENTITY(1, 1) PRIMARY KEY CLUSTERED "
flds &= comma & dr.GetName(i)
Else

'Sql Server 2008 doesn't like a field name "user", so translate this field name into "username"
If dr.GetName(i) = "user" Then
Sql &= comma & " username "
Else
Sql &= comma & dr.GetName(i) & " "
End If

'Now the Sql Statement contains the field name. Now add the field type.

'If the fieldname of my table is "xml", I want to make it a xml-type. If the name contains "xml", but isn't "xml", like "xml_definition", it has to be of type "text".

If dr.GetName(i).Contains("xml") Then

If dr.GetName(i) = "xml" Then
Sql &= " xml "
Else
Sql &= " text "
End If

Else

'This part was made in trial and error mode. If someone knows a better solution, please This e-mail address is being protected from spambots. You need JavaScript enabled to view it .

'Although I don't like the code very much, it worked fine for the purpose it had to serve.
Select Case dr.GetFieldType(i).ToString.Replace("System.", "")
Case "String"
Sql &= " nvarchar(500) "
Case "Int64", "Int32"
Sql &= " bigint "
Case "Boolean"
Sql &= " tinyint "
Case Else
Sql &= " " & dr.GetFieldType(i).ToString.Replace("System.", "")
End Select
End If

'I allow all fields to be NULL
Sql &= " NULL "

End If

comma = ", " 'After the first field, the comma-variable is changed to ",". As I conatenate it between the fields, this works fine to seperate the fields in an easy way. Other solutions, like defining the fields first in an array, and joining them together with the Join-statement is also possible.

Next

'Don't forget the closing bracket for the SQL-statement
Sql &= ")"

Dim cmdSql As New SqlCommand(Sql, ConnSql)

cmdSql.ExecuteNonQuery()

So, now the table is created, having an identity field called Id.Now Copy the data. But before that, you must tell the Sql Server 2008 database you allow to insert records with an identity field already filled.

Soothing the Identity complaint

Sql Server 2008 will complain about your identity field, if the Identity is defined as in the code above, and if you try to insert data with the Id-field filled. As I want to copy the data from an another database, without changing the identity records, I wanted to sooth the complaints from Sql Server 2008.

Sql = "SET IDENTITY_INSERT " & sTable & "  ON"
cmdSql = New SqlCommand(Sql, ConnSql)

cmdSql.ExecuteNonQuery()

This code does the trick. After filling the table, you can do the reverse:

Sql = "SET IDENTITY_INSERT " & sTable & "  OFF"
cmdSql = New SqlCommand(Sql, ConnSql)

cmdSql.ExecuteNonQuery()

Copy data to the Sql Server 2008 database

Now my tool is ready to copy data from the Sql Server Compact Database to the Sql Server 2008 database.

Dim SkipRec As Boolean = False ' True if record must be skipped

Do While dr.Read 'Loop through data-records

SkipRec = False

'I use the flds-variable I filled in the code above for the INSERT statement as well
Sql = "INSERT INTO " & sTable & " ( " & flds & " ) VALUES ( "
comma = ""

'For each field you have to examine the field type, as you have to place quotes around the strings.
For i As Integer = 0 To dr.FieldCount - 1
If Not IsDBNull(dr.Item(i)) Then
Select Case dr.GetFieldType(i).ToString.Replace("System.", "")
Case "String", "DateTime"
Sql &= comma & " '" & dr.Item(i).ToString.Replace("'", """") & "' "
Case "Boolean"
If dr.Item(i) = False Then
Sql &= comma & " 0 "
Else
Sql &= comma & " 1 "
End If

Case Else
Sql &= comma & dr.Item(i)
End Select
Else

If dr.GetName(i) = "id" Then
SkipRec = True
End If

Sql &= comma & " NULL "

End If
comma = ", "

Next i

Sql &= ")"

If Not SkipRec Then
cmdSql = New SqlCommand(Sql, ConnSql)
cmdSql.ExecuteNonQuery()
End If

Loop

This code worked fine for the situation I stumbled into. I hope you can use it. But it may require some modifications to work for your problem!

 

Last Updated on Friday, 15 January 2010 07:20