Click here to Skip to main content
6,629,377 members and growing! (18,264 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), ADO.NET, Dev
Posted:10 Mar 2008
Updated:19 Mar 2008
Views:36,640
Bookmarked:68 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
25 votes for this article.
Popularity: 6.39 Rating: 4.57 out of 5

1
1 vote, 4.0%
2
1 vote, 4.0%
3
1 vote, 4.0%
4
22 votes, 88.0%
5


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


Member

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

Other popular VB.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 26 (Total in Forum: 26) (Refresh)FirstPrevNext
QuestionExport to Excel file ... PinmemberGanesan 20094:08 28 Jul '09  
AnswerRe: Export to Excel file ... PinmemberDennis Betten22:18 2 Aug '09  
AnswerRe: Export to Excel file ... Pinmembergg42371:33 13 Nov '09  
QuestionIndexing xlCells PinmemberPhellipe Schelotag3:17 29 Jul '08  
QuestionStill need HELP PinmemberPhellipe Schelotag10:40 24 Jul '08  
AnswerRe: Still need HELP PinmemberDennis Betten21:51 24 Jul '08  
GeneralRe: Still need HELP PinmemberPhellipe Schelotag3:14 25 Jul '08  
GeneralExcel Automation PinmemberBarbaMariolino1:39 15 May '08  
GeneralRe: Excel Automation PinmemberDennis Betten3:46 15 May '08  
GeneralUnspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)) on 5th table Pinmemberjmoschak12:49 25 Mar '08  
GeneralRe: Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)) on 5th table PinmemberDennis Betten15:17 25 Mar '08  
Generalfaster conversion DataSet.CreateDataReader PinmemberThanks for all the fish5:25 20 Mar '08  
GeneralRe: faster conversion DataSet.CreateDataReader PinmemberDennis Betten2:14 21 Mar '08  
GeneralVery nice! Example project works great. PinmemberKevinStein15:29 19 Mar '08  
QuestionNice work! How about some demo code... Pinmemberoneshoe5:31 18 Mar '08  
GeneralRe: Nice work! How about some demo code... PinmemberDennis Betten5:40 18 Mar '08  
GeneralRe: Nice work! How about some demo code... Pinmemberoneshoe6:53 18 Mar '08  
GeneralRe: Nice work! How about some demo code... PinmemberDennis Betten13:30 19 Mar '08  
GeneralRe: Nice work! How about some demo code... Pinmemberoneshoe4:27 20 Mar '08  
GeneralGreat!! PinmemberGerrit de Vries1:53 15 Mar '08  
GeneralRe: Great!! PinmemberDennis Betten2:10 15 Mar '08  
GeneralRe: Great!! PinmemberEvan Nickels2:17 2 Apr '08  
GeneralNot for very big dbs though PinmemberCaptain Scarlet6:29 10 Mar '08  
GeneralRe: Not for very big dbs though [modified] PinmemberDennis Betten6:51 10 Mar '08  
GeneralRe: Not for very big dbs though PinmemberMember 16439392:37 18 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-2009
Web22 | Advertise on the Code Project