cmiles – blog

Charles Miles – Tucson Hiking, Outside and Adventures, Excel, .net, Life

.net DataTable to ADO Recordset to PivotCache Recordset

PivotTables are a powerful tool in Excel – one interesting feature is the ability to use large sets of data without having the raw data present on an Excel Worksheet or available through the connection types that Excel/Microsoft provide. This expands the number of possible datasources and frees the PivotTable from the data storage limits of a single worksheet.

The PivotCache.Recordset property is the key to this functionality, it takes an ADO recordset and uses it as the data for the PivotTable (from your language of choice!). Good stuff – but this poses an immediate problem in .net code if you are restricted to/committed to getting your data via ADO.NET – how to create the ADO recordset?

There are two possible solutions that I have found –

XML Conversion
One approach to the problem is to use XML and transform the data. I think the links below provide good information and code for this method.

http://support.microsoft.com/kb/316337/
http://www.codeproject.com/dotnet/ADOConversion.asp
http://codebetter.com/blogs/brendan.tompkins/archive/2004/04/27/12229.aspx

‘Direct’ Conversion
The XML solutions above are fascinating – but in my own code I liked the approach that is covered in this article:

http://www.codeproject.com/cs/database/DataTableToRecordset.asp

My coding skills are NOT good enough to easily follow the xml conversion examples – likely part of the reason that I am partial to the ‘Direct’ approach. However, even if your xml coding knowledge is vastly superior to mine, it is interesting to notice the difference in code length and complexity between the XML solutions (longer/more complex) and direct conversion method (shorter/simple!).

I have used the code below for several months in an application that: creates a datatable from a query to a user-instance of SQL Express 2005 (using ADO.NET), converts the datatable (with the code below) into an ADO recordset and pushes it into an Excel PivotTable via the RecordSet property. Performance may be an issue in some situations – in my application there is certainly a pause during the conversion process, but at this point it seems acceptable (the conversion does not seem to take any longer than getting the queried data from the DB).


Imports System.Data
Imports System.IO
Imports Microsoft.Office.Interop
 
 
Public Class ConvertDataTableToAdoRs
 
  Public Shared Function ConvertToRecordset(ByVal inTable As DataTable) _
    As ADODB.Recordset
 
    '=============================================
    '
    'This is a VB conversion of the code found here:
    'http://www.codeproject.com/cs/database/DataTableToRecordset.asp 
    'Please see the original link for a C# version and to read the 
    'original article.
    '
    '=============================================
 
    Dim result As ADODB.Recordset = 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, _
          ADODB.FieldAttributeEnum.adFldIsNullable, _
          Nothing)
    Next
 
    result.Open(System.Reflection.Missing.Value _
            , System.Reflection.Missing.Value _
            , ADODB.CursorTypeEnum.adOpenStatic _
            , ADODB.LockTypeEnum.adLockOptimistic)
 
    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
 
 
 
  Shared Function TranslateType(ByVal columnType As Type) As ADODB.DataTypeEnum
    Select Case columnType.UnderlyingSystemType.ToString()
 
      '=============================================
      '
      'This is a VB conversion of the code found here:
      'http://www.codeproject.com/cs/database/DataTableToRecordset.asp 
      'Please see the original link for a C# version and to read the 
      'original article.
      '
      '=============================================
 
      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
 
    End Select
 
    'Note Strings are not cased and will return here:
    Return ADODB.DataTypeEnum.adVarChar
 
  End Function
 
 
  Public Shared Sub DataTableToRange(ByVal anchorCell As Excel.Range, _
  ByVal tableToCopy As DataTable, _
  Optional ByVal tableHeader As String = "")
 
    If tableHeader <> "" Then
      Try
        anchorCell.Value = tableHeader
        anchorCell = anchorCell.Offset(1, 0)
      Catch ex As Exception
      End Try
    End If
 
    Dim tableHeaderOffset As Integer = 0
 
    For Each loopHeaders As DataColumn In tableToCopy.Columns
      Try
        anchorCell.Offset(0, tableHeaderOffset).Value = loopHeaders.ColumnName
      Catch ex As Exception
      End Try
 
      tableHeaderOffset += 1
 
    Next
 
    anchorCell.Offset(1, 0).CopyFromRecordset(ConvertToRecordset(tableToCopy))
 
  End Sub
 
End Class

The last function in this class is an interesting way to get information in Excel – certainly there are many other ways to get data into Excel from a DataTable without conversion to an ADO recordset. However, DataTableToRange is quick and easy with the conversion code written and ready-to-use.

Comments welcome!
CM

Advertisement

Filed under: .net, Excel

4 Responses

  1. Thank you very much for the useful code !
    Best regards,
    Luc VDP

  2. Ola says:

    Excellent, very helpful indeed! Thanks a lot, appreciate this article.

  3. Geco says:

    This is GREAT code!!!!!; I was looking for this long time ago
    I had a problem when, in some field; there are special caracters like “�”(This char come for other systems), but it was easy to solve

  4. cmiles says:

    Geco – Glad this was helpful and that you were able to easily solve your special characters problem. I have made some small changes over the years, but I am still using this basic solution!

    CM

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

twitter -> twitterings

  • Just saw the new Resharper 6.1 Early Access version has Async CTP support listed - downloading now... 2 months ago
  • Quick post about FeedDemon/Pinboard/Save to Pinboard on Android as my choice for Google Reader Sharing http://t.co/EupWQupM 3 months ago
  • FeedDemon+Custom Sharing XML->Pinboard; NewsRob + Save to Pinboard on Android - replacing Google Reader sharing, Reader now just for sync... 3 months ago
  • Doing a few Max - http://t.co/wL8dpWk4 - tutorials - what fun, first time in a decade I have played with this... 4 months ago

RSS pinboard -> links

RSS cmiles-consuming -> posts

  • Beats, Rhymes & Life: The Travels of a Tribe Called Quest 2012 January 30
    I have no idea when I first heard a Tribe Called Quest (official site) – but it was the early 2000s before I really ‘found’ them and started listening. I would not call myself a devotee – casual fan is probably the best description – but even as a casual fan I was excited when [...]
  • Hull Zero Three, Greg Bear 2012 January 15
    I am sad to say that the first time I saw Hull Zero Three by Greg Bear (official site) on Amazon I skipped over it because of the rating – in retrospect a somewhat sad reminder to myself about the value of ratings… Thankfully on the Potpourri of Science Fiction Literature blog I came across [...]
  • Happy New Year! End of 2011 Notes… 2012 January 1
    This blog made it thru 2011! A few notes about my media/reading that I thought might be fun if this blogs lasts a few years… -Reading: I am mostly reading on my Sprint Evo 4G Android Phone via the Kindle app. While the reading experience on such a small screen is unexciting the compelling feature [...]
  • Revelation Space Universe, Alastair Reynolds 2011 December 31
    I don’t have a good enough memory or record of what I was reading in the late 1990s or early 2000s to know if this is the truth – but the way I remember it is that after a lull where I had trouble finding any science fiction I was interested in reading I came [...]
  • Sea of Glass, Barry B. Longyear 2011 December 20
    I don’t remember seeing Sea of Glass, by Barry B. Longyear, on ‘top’ science fiction lists – or stumbling across it in website recommendations; but I do remember this novel from reading it in (about…) 1990. What I remember is the brutality, terror and a dystopian future world on the brink of war. The novel [...]
  • String Quartets 2 & 3, Kevin Volans, Balanescu Quartet, Kronos Quartet 2011 December 12
    I believe I first heard Kevin Volans‘s (homepage) String Quartet No. 2 – ‘Hunting: Gathering’ in the mid-1990s on a Kronos Quartet CD. While I can not say this was immediately one of my favorite pieces, I will say that sounds from and sections of the 2nd String Quartet have stayed with me – coming [...]
  • Norwegian Wood, Haruki Murakami 2011 December 6
    Norwegian Wood was not quite what I was expecting – the Murakami novels that I have read – A Wild Sheep Chase, Hard-Boiled Wonderland and the End of the World, Dance Dance Dance, The Wind-Up Bird Chronicle, Sputnik Sweetheart, Kafka on the Shore and After Dark – all seem to me to have some place [...]
  • Looking Glass, James R Strickland 2011 November 27
    Cyberpunk! James Strickland delivers the classic elements in Looking Glass – a future United States now carved into different countries, powerful corporations, cyber space, techy jargon, decks, jacking in and action! The strength of this novel is not in offering something insightful and new – but rather in being an intelligent and fascinating rec […]
  • Await Your Reply, Dan Chaon 2011 November 21
    Dan Chaon gives us a clever plot – with several converging stories – and disturbed characters that work together to create an enjoyable and slightly uncomfortable novel. There were sections that certainly made me think about my own life and identity, but overall I was not quite completely hooked/pulled in. Rating: 3 of 5 First [...]
  • Running the Sahara 2011 November 16
    Running the Sahara – directed by James Moll – follows three athletes as they run across the Sahara Desert. They run (and sometimes walk) thru Senegal, Mauritania, Mali, Niger, Libya and Egypt. The film does a great job of showing some of the amazing landscapes that they cross – with small glimpses of the people [...]
email: charles@cmiles.info

flickr -> pictures

1202 Group Picture 2 after the Colossal Cave Run

1202 Group Picture 1 after the Colossal Cave Race

1202 Charles And Joe After the Colossal Cave Run

1201 View from about 4 miles down the trail

1201 Water coming down Sycamore Dam

1201 Life of an Outdoor Footwear Buyer

1201 Blacketts Ridge Night Run, Dana near the top

1201 Arizona Trail in the Colossal Cave Area (Rincon Valley)

1201 Richard Coming Up to hill after the turn off the AZ Trail

1112 Sunset from Pontatoc Canyon

More Photos
Follow

Get every new post delivered to your Inbox.