Friday, January 29, 2010

Export complete database to excel file


First of all, I need to give some credit to Marc Brooks for publishing code which made it possible for me to make my code about a hundred times faster as it originaly was!

What does this code do:
As the title says, this code is capable of extracting all tables and it's data from any given SQL database and export it to Excel! Every table gets it's own worksheet. I was searching the net for a program like this, but I didn't come accross any (free) versions. So I decided to write it myself.
Using the code

To get this code to work, you need to add a reference to Excel.dll by using Add Reference on the project and selecting Microsoft Excel 9.0 (or 10.0) Object Library from the COM tab on the Add Reference dialog.

And then import the following namespace:

Imports System.Runtime.InteropServices.Marshal

Now add the following class to your project:

Private Sub create(ByVal sDatabaseName As String)
Dim dsTables As DataSet = New DataSet

'Get all Tables from database
dsTables = getAllTables(sDatabaseName)
'Create Excel Application, Workbook, and WorkSheets
Dim xlExcel As New Excel.Application
Dim xlBooks As Excel.Workbooks
Dim xlBook As Excel.Workbook
Dim tblSheet As Excel.Worksheet
Dim xlCells As Excel.Range
Dim sFile As String
'File name for the excel files
File = Server.MapPath(sDatabaseName & "_data.xls")
xlExcel.Visible = False : xlExcel.DisplayAlerts = False
xlBooks = xlExcel.Workbooks
xlBook = xlBooks.Add

For i As Integer = 0 To dsTables.Tables.Count - 1
tblSheet = xlBook.Worksheets.Add
tblSheet.Name = dsTables.Tables(i).TableName
xlCells = tblSheet.Cells
For iCol As Integer = 0 To dsTables.Tables(i).Columns.Count - 1
xlCells(1, iCol + 1) = dsTables.Tables(i).Columns(iCol).ToString
xlCells(1).EntireRow.Font.Bold = True
If dsTables.Tables(i).Rows.Count > 0 Then
'With ConvertToRecordset the datatable is converted to a recordset
'Then with CopyFromRecordset the entire recordset can be inserted at once
End If

'Remove initial excel sheets. Within a try catch because the database
'could be empty (a workbook without worksheets is not allowed)
Dim SheetCount As Integer = xlExcel.Sheets.Count
CType(xlExcel.Sheets(SheetCount - 0), Excel.Worksheet).Delete()
CType(xlExcel.Sheets(SheetCount - 1), Excel.Worksheet).Delete()
CType(xlExcel.Sheets(SheetCount - 2), Excel.Worksheet).Delete()
Catch ex As Exception
End Try

'Save the excel file

'Make sure all objects are disposed
xlExcel = Nothing
xlBooks = Nothing
xlBook = Nothing
tblSheet = Nothing
xlCells = Nothing

'Let the Garbage Collector know it can get to work

'Export Excel for download
HttpContext.Current.Response.ContentType = "application/octet-stream"
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(sFile))
Catch ex As Exception
End Try
End Sub

To convert the DataTable to a recordset, the following two classes are used:

Private Shared Function ConvertToRecordset(ByVal inTable As DataTable) As ADODB.Recordset
Dim result As New ADODB.Recordset()
result.CursorLocation = ADODB.CursorLocationEnum.adUseClient
Dim resultFields As ADODB.Fields = result.Fields
Dim inColumns As System.Data.DataColumnCollection = inTable.Columns

For Each inColumn As DataColumn In inColumns
resultFields.Append(inColumn.ColumnName, TranslateType(inColumn.DataType), inColumn.MaxLength, IIf(inColumn.AllowDBNull, _
ADODB.FieldAttributeEnum.adFldIsNullable, ADODB.FieldAttributeEnum.adFldUnspecified), Nothing)

result.Open(System.Reflection.Missing.Value, System.Reflection.Missing.Value, ADODB.CursorTypeEnum.adOpenStatic, _
ADODB.LockTypeEnum.adLockOptimistic, 0)

For Each dr As DataRow In inTable.Rows
result.AddNew(System.Reflection.Missing.Value, System.Reflection.Missing.Value)
For columnIndex As Integer = 0 To inColumns.Count - 1
resultFields(columnIndex).Value = dr(columnIndex)
Return result
End Function

Private Shared Function TranslateType(ByVal columnType As Type) As ADODB.DataTypeEnum
Select Case columnType.UnderlyingSystemType.ToString()
Case "System.Boolean"
Return ADODB.DataTypeEnum.adBoolean
Case "System.Byte"
Return ADODB.DataTypeEnum.adUnsignedTinyInt
Case "System.Char"
Return ADODB.DataTypeEnum.adChar
Case "System.DateTime"
Return ADODB.DataTypeEnum.adDate
Case "System.Decimal"
Return ADODB.DataTypeEnum.adCurrency
Case "System.Double"
Return ADODB.DataTypeEnum.adDouble
Case "System.Int16"
Return ADODB.DataTypeEnum.adSmallInt
Case "System.Int32"
Return ADODB.DataTypeEnum.adInteger
Case "System.Int64"
Return ADODB.DataTypeEnum.adBigInt
Case "System.SByte"
Return ADODB.DataTypeEnum.adTinyInt
Case "System.Single"
Return ADODB.DataTypeEnum.adSingle
Case "System.UInt16"
Return ADODB.DataTypeEnum.adUnsignedSmallInt
Case "System.UInt32"
Return ADODB.DataTypeEnum.adUnsignedInt
Case "System.UInt64"
Return ADODB.DataTypeEnum.adUnsignedBigInt
Case "System.String"
Return ADODB.DataTypeEnum.adVarChar
Case Else
Return ADODB.DataTypeEnum.adVarChar
End Select
End Function

And now the trick to getting all tables and data from a database:

Public database as String

Public ReadOnly Property getAllTables(ByVal sDB As String) As DataSet
database = sDB
Dim m_dshelp As DataSet = New DataSet
Return m_dshelp
End Get
End Property

Private Function getRequestedAllTables(ByRef p_dataset As DataSet) As Boolean
'Retrieve all tablenames from the database:
Dim sSQL As String
Dim dsTables As DataSet = New DataSet

sSQL = "SELECT [TableName] =, [RowCount] = MAX(si.rows) " & _
"FROM sysobjects so, sysindexes si " & _
"WHERE so.xtype = 'U' AND = OBJECT_ID( AND si.rows > 0 " & _
"GROUP BY " & _

getData(sSQL, "Tables", dsTables)
'Loop thrue all tables and do a SELECT *. Then add them to the dataset
For i As Integer = 0 To dsTables.Tables(0).Rows.Count - 1
sSQL = "SELECT * FROM " & dsTables.Tables(0).Rows(i).Item(0)
getData(sSQL, dsTables.Tables(0).Rows(i).Item(0), p_dataset)
End Function

Private Function getData(ByVal p_sql As String, ByVal p_table As String, ByRef pdataset As DataSet) As Boolean
Dim objDataAdapter As SqlDataAdapter
Dim objcommand As SqlCommand
objcommand = New SqlCommand(p_sql, getConnection)
objDataAdapter = New SqlDataAdapter(objcommand)
objDataAdapter.Fill(pdataset, p_table)
End Function

Private Function getConnection() As SqlConnection
If (ConfigurationManager.AppSettings("SQLPW") <> "") Then
getConnection = New SqlConnection("Server=" & _
ConfigurationManager.AppSettings("SQLserver") & ";password=" & _
ConfigurationManager.AppSettings("SQLPW") & "; user=" & _
ConfigurationManager.AppSettings("SQLUser") & ";database=" & database)
getConnection = New SqlConnection("Data Source=" & _
ConfigurationManager.AppSettings("SQLserver") & ";Initial Catalog=" & _
database & ";Integrated Security=True")
End If
End Function


No comments:

Post a Comment