Export datatable to Excel

  • Thread starter Thread starter Rob Oldfield
  • Start date Start date
R

Rob Oldfield

I have a datatable (created in a vb Windows forms app) and I want to export
it to Excel. I've looked at...

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q295646

....where it suggests using something like....

Dim strSQL As String
strSQL = "SELECT * INTO [Excel 8.0;Database=" & App.Path & _
"\book1.xls].[Sheet1] FROM Customers"
cnSrc.Execute strSQL

....but I just have the datatable that I've created (i.e. it only exists in
my app). How do I refer to that datatable to replace the connection string
connecting up to the Customers table.

(Note: I can already export by doing it by going through the datasource row
by row.... but that seems inefficient. I want to do it in one go.)

Any ideas?
 
I wrote this procedure to export a datatable to Excel.
It works pretty well, but has a minor problem with closing the instance of
Excel.
Let me know if it works for you and if you have solved the problem!

Public Sub Export2Excel(ByVal dt As DataTable, ByVal strPath As String,
ByRef pb As ProgressBar, ByVal MyOption As String)

'add reference to Microsoft Excel

Dim objXL As Excel.Application

Dim objWBS As Excel.Workbooks

Dim objWB As Excel.Workbook

Dim objWS As Excel.Worksheet

Dim mRow As DataRow

Dim colIndex As Integer

Dim rowIndex As Integer

Dim col As DataColumn

're-set pb so it displays correctly if called again

pb.Value = 0

pb.Minimum = 0

pb.Step = 1

Try

pb.Maximum = dt.Rows.Count

pb.Visible = True

If File.Exists(strPath) Then

File.Delete(strPath)

End If

Try

'get a running instance of Excel - this minimizes the number of instances of
Excel in memory!

objXL = CType(GetObject(, "Excel.Application"), Excel.Application)

Catch ex As Exception

'create a new instance of Excel if there isn't one running.

objXL = New Excel.Application

End Try

objWBS = objXL.Workbooks

objWB = objWBS.Add

objWS = CType(objWB.Worksheets(1), Excel.Worksheet)

'write column headers to Excel's first row from the dt.

For Each col In dt.Columns

colIndex += 1

objWS.Cells(1, colIndex) = col.ColumnName

Next col

If MyOption = "A" Then

'Bold and widen all the column headings

objWS.Range("A1:X1").Font.Bold = True

objWS.Columns.ColumnWidth = 10.5

'make some columns wider than the others

objWS.Range("A:A").ColumnWidth = 17

objWS.Range("C:C").ColumnWidth = 39

objWS.Range("E:F").ColumnWidth = 20

objWS.Range("L:O").ColumnWidth = 20

objWS.Range("T:T").ColumnWidth = 13

'rename the sheet to the file name w/o extension

objWS.Name = Mid(Path.GetFileName(strPath), 1,
Len(Path.GetFileName(strPath)) - 4)

ElseIf MyOption = "B" Then

'Bold and widen all the column headings

objWS.Range("A1:Q1").Font.Bold = True

objWS.Columns.ColumnWidth = 10.5

'make a column wider

objWS.Range("A:A").ColumnWidth = 17

'rename the sheet to B

objWS.Name = "B"

Else

'do nothing

End If

'write data starting on row with column headers because the first step is to
increment to the next row.

rowIndex = 1

For Each mRow In dt.Rows

pb.PerformStep()

rowIndex += 1

colIndex = 0

For Each col In dt.Columns

colIndex += 1

If col.ColumnName = "field1" Or col.ColumnName = "field2" Or col.ColumnName
= "field3" Then

'force to text data by adding a leading apostrophe

objWS.Cells(rowIndex, colIndex) = "'" & mRow(col.ColumnName).ToString()

Else

objWS.Cells(rowIndex, colIndex) = mRow(col.ColumnName).ToString()

End If

Next col

Next mRow

'make all rows same height

objWS.Range("A1:A" & CStr(dt.Rows.Count)).RowHeight = 12.75

objWB.SaveAs(strPath)

objWB.Close()

'minor problem - Excel is staying in Memory even after the Quit. It goes
away when the form is closed.

'if this procedure was local to the form that called it the problem might go
away. Untested.

'partially fixed by using a running instance instead of creating a new one
every time.

'Limited to 1 instance stuck in memory instead of unlimited number.

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWS)

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWB)

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWBS)

objXL.Quit()

System.Runtime.InteropServices.Marshal.ReleaseComObject(objXL)

'this does not work to clear out the Excel instance from memory. Even though
it looks like "just the thing".

'http://www.dotnetinterop.com/faq/?q=OfficeCleanup

'http://support.microsoft.com/default.aspx?scid=kb;en-us;317109

'release other objects too! Still does not work. May be the remote call
issue.


Catch exc As Exception

Throw

Finally

objWS = Nothing

objWB = Nothing

objWBS = Nothing

objXL = Nothing

pb.Visible = False

'this does not work to clear out the Excel instance from memory either.

'GC.Collect()

'GC.WaitForPendingFinalizers()

End Try

End Sub

--
Joe Fallon




Rob Oldfield said:
I have a datatable (created in a vb Windows forms app) and I want to export
it to Excel. I've looked at...

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q295646

...where it suggests using something like....

Dim strSQL As String
strSQL = "SELECT * INTO [Excel 8.0;Database=" & App.Path & _
"\book1.xls].[Sheet1] FROM Customers"
cnSrc.Execute strSQL

...but I just have the datatable that I've created (i.e. it only exists in
my app). How do I refer to that datatable to replace the connection string
connecting up to the Customers table.

(Note: I can already export by doing it by going through the datasource row
by row.... but that seems inefficient. I want to do it in one go.)

Any ideas?
 
Hi Rob,

You can always save a dataset as
mydataset.writexml(mypath)

And load that in the Excel versions which can read XML (not the old ones).

I hope this helps?

Cor
 
That's exactly the kind of stuff that I'm looking for, but sadly I'm using
Excel 2000.
 
Thanks for that Joe. I already have various apps that push data to Excel by
looping through on a row by row basis (although I tend to go for ADO rather
than automation), I was really looking for a more efficient way of doing it.
Something like Cor's suggestion (but compatible with Excel 2K) is really
what I'm after.


Joe Fallon said:
I wrote this procedure to export a datatable to Excel.
It works pretty well, but has a minor problem with closing the instance of
Excel.
Let me know if it works for you and if you have solved the problem!

Public Sub Export2Excel(ByVal dt As DataTable, ByVal strPath As String,
ByRef pb As ProgressBar, ByVal MyOption As String)

'add reference to Microsoft Excel

Dim objXL As Excel.Application

Dim objWBS As Excel.Workbooks

Dim objWB As Excel.Workbook

Dim objWS As Excel.Worksheet

Dim mRow As DataRow

Dim colIndex As Integer

Dim rowIndex As Integer

Dim col As DataColumn

're-set pb so it displays correctly if called again

pb.Value = 0

pb.Minimum = 0

pb.Step = 1

Try

pb.Maximum = dt.Rows.Count

pb.Visible = True

If File.Exists(strPath) Then

File.Delete(strPath)

End If

Try

'get a running instance of Excel - this minimizes the number of instances of
Excel in memory!

objXL = CType(GetObject(, "Excel.Application"), Excel.Application)

Catch ex As Exception

'create a new instance of Excel if there isn't one running.

objXL = New Excel.Application

End Try

objWBS = objXL.Workbooks

objWB = objWBS.Add

objWS = CType(objWB.Worksheets(1), Excel.Worksheet)

'write column headers to Excel's first row from the dt.

For Each col In dt.Columns

colIndex += 1

objWS.Cells(1, colIndex) = col.ColumnName

Next col

If MyOption = "A" Then

'Bold and widen all the column headings

objWS.Range("A1:X1").Font.Bold = True

objWS.Columns.ColumnWidth = 10.5

'make some columns wider than the others

objWS.Range("A:A").ColumnWidth = 17

objWS.Range("C:C").ColumnWidth = 39

objWS.Range("E:F").ColumnWidth = 20

objWS.Range("L:O").ColumnWidth = 20

objWS.Range("T:T").ColumnWidth = 13

'rename the sheet to the file name w/o extension

objWS.Name = Mid(Path.GetFileName(strPath), 1,
Len(Path.GetFileName(strPath)) - 4)

ElseIf MyOption = "B" Then

'Bold and widen all the column headings

objWS.Range("A1:Q1").Font.Bold = True

objWS.Columns.ColumnWidth = 10.5

'make a column wider

objWS.Range("A:A").ColumnWidth = 17

'rename the sheet to B

objWS.Name = "B"

Else

'do nothing

End If

'write data starting on row with column headers because the first step is to
increment to the next row.

rowIndex = 1

For Each mRow In dt.Rows

pb.PerformStep()

rowIndex += 1

colIndex = 0

For Each col In dt.Columns

colIndex += 1

If col.ColumnName = "field1" Or col.ColumnName = "field2" Or col.ColumnName
= "field3" Then

'force to text data by adding a leading apostrophe

objWS.Cells(rowIndex, colIndex) = "'" & mRow(col.ColumnName).ToString()

Else

objWS.Cells(rowIndex, colIndex) = mRow(col.ColumnName).ToString()

End If

Next col

Next mRow

'make all rows same height

objWS.Range("A1:A" & CStr(dt.Rows.Count)).RowHeight = 12.75

objWB.SaveAs(strPath)

objWB.Close()

'minor problem - Excel is staying in Memory even after the Quit. It goes
away when the form is closed.

'if this procedure was local to the form that called it the problem might go
away. Untested.

'partially fixed by using a running instance instead of creating a new one
every time.

'Limited to 1 instance stuck in memory instead of unlimited number.

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWS)

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWB)

System.Runtime.InteropServices.Marshal.ReleaseComObject(objWBS)

objXL.Quit()

System.Runtime.InteropServices.Marshal.ReleaseComObject(objXL)

'this does not work to clear out the Excel instance from memory. Even though
it looks like "just the thing".

'http://www.dotnetinterop.com/faq/?q=OfficeCleanup

'http://support.microsoft.com/default.aspx?scid=kb;en-us;317109

'release other objects too! Still does not work. May be the remote call
issue.


Catch exc As Exception

Throw

Finally

objWS = Nothing

objWB = Nothing

objWBS = Nothing

objXL = Nothing

pb.Visible = False

'this does not work to clear out the Excel instance from memory either.

'GC.Collect()

'GC.WaitForPendingFinalizers()

End Try

End Sub

--
Joe Fallon




in message news:Om2cUAX%[email protected]...
I have a datatable (created in a vb Windows forms app) and I want to export
it to Excel. I've looked at...

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q295646

...where it suggests using something like....

Dim strSQL As String
strSQL = "SELECT * INTO [Excel 8.0;Database=" & App.Path & _
"\book1.xls].[Sheet1] FROM Customers"
cnSrc.Execute strSQL

...but I just have the datatable that I've created (i.e. it only exists in
my app). How do I refer to that datatable to replace the connection string
connecting up to the Customers table.

(Note: I can already export by doing it by going through the datasource row
by row.... but that seems inefficient. I want to do it in one go.)

Any ideas?
 
Hi Rob,

But it is not that much work to make a csv file from a dataset, it is also
looping, but so easy.

I made it once for Scorpion.

Is a generic version, and fast as possible (it is using the arraylist and
the stringbuilder), not so slow as using interop.

But you have to test it of course.

Cor

\\\
Dim Scorpion As New ArrayList
For i As Integer = 0 To ds.Tables("scorpion").Rows.Count - 1
Dim row As New System.Text.StringBuilder
Scorpion.Add(row)
row.append("""")
For y As Integer = 0 To ds.Tables("scorpion").Columns.Count - 1
row.Append(ds.Tables("scorpion").Rows(i)(y).tostring)
If y <> ds.Tables("scorpion").Columns.Count - 1 Then
row.Append(""",""")
' if you want it with a tab
' row.Append("""")
' row.Append(chr(09))
' row.Append("""")
else
row.Append("""")
End If
Next
Next
Dim sw As New IO.StreamWriter("C:\Scorpion.csv")
For i As Integer = 0 To Scorpion.Count - 1
sw.WriteLine(Scorpion(i).ToString)
Next
sw.Flush()
sw.Close()
///


Cor
 
Hmmmm. I find it a little strange that there isn't a better method of doing
the entire export all in one go, but I suppose we'll just have to live with
it.

The end result of this particular app will, in fact, be a csv file so your
example code should be useful. Thanks again.
 
Hi Rob,

I have a component, which
allows to export data from ADO.NET DataSets/DataTables into native or
Excel XML file format without any providers. It works fast and
requires minimum coding. If you are interested in it, let me know and
I could send you a demo version of it.
 
Back
Top