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

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:

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... 6 months ago
  • Quick post about FeedDemon/Pinboard/Save to Pinboard on Android as my choice for Google Reader Sharing cmiles.info/2011/11/05/goo… 6 months ago
  • FeedDemon+Custom Sharing XML->Pinboard; NewsRob + Save to Pinboard on Android - replacing Google Reader sharing, Reader now just for sync... 7 months ago
  • Doing a few Max - cycling74.com - tutorials - what fun, first time in a decade I have played with this... 7 months ago

RSS pinboard -> links

  • Gmap4 - Share Enhanced Google Maps
    A very cool tool - free for non-commercial use - that can produce very nice (and very usable) topo maps that can have data (GPX, KML,...) overlaid on it very easily!
  • Vistoso Hiking Club Hikes Database
    Short descriptions of hikes near Tucson with a few off trail and interesting destinations - no doubt there are more informative sources but sometimes the simplest thing is nice...
  • Bill Hill - Pictures
    I don't stumble on that many well organized great sets of Tucson hiking photos so saving this link!
  • [WPF] How to bind to data when the DataContext is not inherited
    This solved a problem for me with control of DataGrid Column visibility via Data Binding. Did not test/research/profile this extensively, but for my problem this worked like a charm.

RSS cmiles-consuming -> posts

  • Kafka on the Shore and The Wind-Up Bird Chronicle, Haruki Murakami 2012 June 1
    Kafka on the Shore and The Wind-Up Bird Chronicle by Haruki Murakami are favorites of mine. To combine them into one blog post seems slightly odd – they are not part of a series and are complex enough that reducing them down to a few sentences seems like a disservice. But what these have in [...]
  • Hyperion and The Fall of Hyperion, Dan Simmons 2012 May 16
    I first read Dan Simmons‘s Hyperion in the early 1990s – the Hyperion Cantos is quite famous and I would occasionally see Hyperion listed in Amazon recommendations and ‘top’ lists (see the ISFDB Top 100 Lists and Your Picks: Top 100 Science-Fiction, Fantasy Books from npr books (note that you may get some amusement out [...]
  • Wool Omnibus (Wool 1-5), Hugh Howey 2012 May 1
    I don’t usually pay much attention to Amazon’s recommendations – but after finishing 1Q84 I wanted something new and, for whatever reason, the Wool Omnibus by Hugh Howey jumped out at me on Amazon’s list. Wool takes place in a bleak future where the characters live in self sufficient underground silos with only a vague [...]
  • 1Q84, Haruki Murakami 2012 April 15
    I am a fan of Haruki Murakami, so I was excited when the English version of 1Q84 became available. I picked up and put down this book several times while reading it and I have to admit that I just really don’t know what to say about it – Long/Interesting/What?/I am glad I read it/Why?/1984/hmmm… [...]
  • Ride the Divide 2012 April 2
    Ride the Divide has great scenery, interesting people, injuries, struggles and riding along the Great Divide Mountain Bike Route that goes from Banff, Canada to the Mexican border! While I am familiar with some of the long distance hiking trails in the US I had no idea this route existed and it was fascinating to [...]
  • Forks over Knives 2012 March 20
    Forks over Knives (official website), directed by Lee Fulkerson, is a rather long documentary with the singular message that plant based diets are better than meat based diets (it may be slightly more subtle than that, but I think that is a pretty fair summary). I watched the film days after seeing Tabloid and could [...]
  • Tabloid, The Thin Blue Line 2012 March 15
    Tabloid – by Errol Morris – is the story of Joyce McKinney. McKinney was involved in a widely publicized case/scandal/incident in England in the late 1970s sometimes given the colorful name ‘The Case of the Manacled Mormon’. I had no knowledge of the events prior to the film – which might have added to the [...]
  • Jig 2012 March 1
    Jig follows a number of dancers leading up to their participation in the 40th Irish Dancing World Championships (2010). This film is a friendly, short and entertaining glimpse into a world that I did not know even existed – great fun. Simple, good! Rating: 4 of 5 First Watch Date: December 2011 CM
  • 180° South: Conquerors of the Useless 2012 February 16
    180° South: Conquerors of the Useless (official site) direct by Chris Malloy follows the journey of Jeff Johnson from Ventura, California to the Corcovado Volcano in Patagonia. The film has some amazing footage of Patagonia and interesting people (including Yvon Chouinard and Douglas Tompkins) – but, somehow, it didn’t hold my interest… Too […]
  • 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 [...]
email: charles@cmiles.info

flickr -> pictures

1205 Looking down Pontatoc Canyon

1205 Looking up canyon from the end of the Pontatoc Canyon Trail

1205 Pontatoc Canyon End of Trail Sign

1205 Looking up at the rocks above the end of the Pontatoc Canyon Trail

1205 Catepillar

1205 Maybe from the fire fighting

1205 Looking back up Sabino Canyon from Brinkley Point

1205 View towards Sabino Canyon from Brinkley Point

1205 Charles and Alison

1205 View from Brinkley Point

More Photos
Follow

Get every new post delivered to your Inbox.