5,696,576 members and growing! (14,649 online)
Email Password   helpLost your password?
Languages » VB.NET » HowTo     Advanced License: The Code Project Open License (CPOL)

Export complete database to excel file

By Dennis Betten

Export all tables and data to one excel file
VB, SQL, Windows, SQL Server (SQL 2005, SQL Server), ADO.NET, Dev

Posted: 10 Mar 2008
Updated: 19 Mar 2008
Views: 19,502
Bookmarked: 44 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
24 votes for this Article.
Popularity: 6.30 Rating: 4.56 out of 5
0 votes, 0.0%
1
1 vote, 4.2%
2
1 vote, 4.2%
3
1 vote, 4.2%
4
21 votes, 87.5%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article


Download an example project here: Download ExportDBtoExcel.zip - 363.35 KB

Introduction

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
        Next
        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 
            tblSheet.Range("A2").CopyFromRecordset(ConvertToRecordset(dsTables.Tables(i)))
        End If
        xlCells.Columns.AutoFit()
    Next 

    'Remove initial excel sheets. Within a try catch because the database 
    'could be empty (a workbook without worksheets is not allowed)
    Try
        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
    xlBook.SaveAs(sFile) 

    'Make sure all objects are disposed
    xlBook.Close()
    xlExcel.Quit()
    ReleaseComObject(xlCells)
    ReleaseComObject(tblSheet)
    ReleaseComObject(xlBook)
    ReleaseComObject(xlBooks)
    ReleaseComObject(xlExcel)
    xlExcel = Nothing
    xlBooks = Nothing
    xlBook = Nothing
    tblSheet = Nothing
    xlCells = Nothing

    'Let the Garbage Collector know it can get to work
    GC.Collect() 

    'Export Excel for download
    Try
        HttpContext.Current.Response.ContentType = "application/octet-stream"
        HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + System.IO.Path.GetFileName(sFile))
        HttpContext.Current.Response.Clear()
        HttpContext.Current.Response.WriteFile(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)
    Next

    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)
        Next
    Next
    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 
    Get
        database = sDB 
        Dim m_dshelp As DataSet = New DataSet
        getRequestedAllTables(m_dshelp) 
        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] = so.name, [RowCount] = MAX(si.rows) " & _
    "FROM sysobjects so, sysindexes si " & _
    "WHERE so.xtype = 'U' AND si.id = OBJECT_ID(so.name) AND si.rows > 0 " & _
    "GROUP BY so.name " & _
    "ORDER BY 2 DESC" 

    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)
    Next
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)
    Else 
        getConnection = New SqlConnection("Data Source=" & _
        ConfigurationManager.AppSettings("SQLserver") & ";Initial Catalog=" & _
        database & ";Integrated Security=True")
    End If
End Function 

Downloadable Example

I've added an example project to this article. The project is created using Visual Studio 2005.

Download ExportDBtoExcel.zip - 363.35 KB

Be sure to check the web.config file and edit the SQLServer settings, when needed.
If you have a basic SQL server running as a (local) server with Integrated Security. And if you have the Northwind database installed, you can just run it and it'll work.

In case you need the code to be in C#, just Google for 'Convert VB.net to C#'.

Limitations

Unfortunately there are some limitations to this code. It has everything to do with limitations to Excel. As long as the table structure and data are conform the following list, everything should work ok:

Subject

Limitation

Worksheet size max 65536 rows, 256 columns
Cell content (text) only 1024 characters in 1 cell
Amount of Worksheets Limited by available memory
SQL TimeStamp field Project can't handle SQL TimeStamp field (yet). But I'm sure there is a way to get it working

That's all there is to it!! Happy Coding!

History

03/10/2008 - First version
03/12/2008 - Added Limitations list
03/14/2008 - Made the code about a hundred times faster by converting datatable to recordset and shooting the data right into the excel sheet, instead of inserting data cell by cell.
03/19/2008 - Added a vs2005 VB.Net Sample project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Dennis Betten



Occupation: Software Developer (Senior)
Company: Sogeti B.V. Netherlands
Location: Netherlands Netherlands

Other popular VB.NET articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 23 of 23 (Total in Forum: 23) (Refresh)FirstPrevNext
QuestionIndexing xlCellsmemberPhellipe Schelotag3:17 29 Jul '08  
QuestionStill need HELPmemberPhellipe Schelotag10:40 24 Jul '08  
AnswerRe: Still need HELPmemberDennis Betten21:51 24 Jul '08  
GeneralRe: Still need HELPmemberPhellipe Schelotag3:14 25 Jul '08  
GeneralExcel AutomationmemberBarbaMariolino1:39 15 May '08  
GeneralRe: Excel AutomationmemberDennis Betten3:46 15 May '08  
GeneralUnspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)) on 5th tablememberjmoschak12:49 25 Mar '08  
GeneralRe: Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)) on 5th tablememberDennis Betten15:17 25 Mar '08  
Generalfaster conversion DataSet.CreateDataReadermemberThanks for all the fish5:25 20 Mar '08  
GeneralRe: faster conversion DataSet.CreateDataReadermemberDennis Betten2:14 21 Mar '08  
GeneralVery nice! Example project works great.memberKevinStein15:29 19 Mar '08  
QuestionNice work! How about some demo code...memberoneshoe5:31 18 Mar '08  
GeneralRe: Nice work! How about some demo code...memberDennis Betten5:40 18 Mar '08  
GeneralRe: Nice work! How about some demo code...memberoneshoe6:53 18 Mar '08  
GeneralRe: Nice work! How about some demo code...memberDennis Betten13:30 19 Mar '08  
GeneralRe: Nice work! How about some demo code...memberoneshoe4:27 20 Mar '08  
GeneralGreat!!memberGerrit de Vries1:53 15 Mar '08  
GeneralRe: Great!!memberDennis Betten2:10 15 Mar '08  
GeneralRe: Great!!memberEvan Nickels2:17 2 Apr '08  
GeneralNot for very big dbs thoughmemberCaptain Scarlet6:29 10 Mar '08  
GeneralRe: Not for very big dbs though [modified]memberDennis Betten6:51 10 Mar '08  
GeneralRe: Not for very big dbs thoughmemberMember 16439392:37 18 Mar '08  
GeneralThis would have been very usefull on my previous projectmemberDavid B. Taylor6:05 10 Mar '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 19 Mar 2008
Editor:
Copyright 2008 by Dennis Betten
Everything else Copyright © CodeProject, 1999-2008
Web18 | Advertise on the Code Project