The PODA Blog

News, views and articles from our membership

Archive for November 20th, 2007

MS Access: A Simple Pivot Table

Posted by Derek Mang on 20th November 2007

One of my clients recently had the need for a management report that presented project information.  These data included project milestone dates, along with some basic project data.  The client's database maintained the main project data and milestone dates in separate tables, where the milestones were in a many-to-one relationship.  The objective was to create a new table with one row per project containing a combination of project descriptive data and milestones.

The client is fairly accomplished with Access, developing forms, queries, etc.., but could not get this one to work as desired. When asked to help out, I was also at a loss.  I knew what the result should be, but could not use Access functionality alone to make it happen.

I did a little research and wound up with sample SQL that would create a PIVOT table.  Unfortunately, I could not combine this with additional SQL to achieve the desired result.

Since time was not in great supply (there's a shock!!), it was VBA to the rescue (another shock!).  The code is found below, and here's what happens:

1. A milestones "Pivot" recordset is created using the TRANSFORM

2. A new table is dynamically created. This table includes the project ID, name, and description fields, and then however many date columns returned in the "PIVOT" recordset.  (Note that the new table is deleted first if already within the set of table) definitions.

3. The new "tabledef" is appended to the database, and the db is refreshed.

4. The new table is opened, and new rows are added based on the projects returned in the original "Pivot" recordset.

I am sharing this mainly because of the elegance of the "TRANSFORM" SQL.  This really made the solution pretty simple, and I now know something new for dealing with similar situations.  Hopefully, others will be able to benefit from my experience.

Visual Basic:
    Dim strSQL As String
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim rs1 As DAO.Recordset
    Dim tbldef As DAO.TableDef
    Dim t As Integer
    Dim rsDates As DAO.Recordset
   
    Const PROJECTINFO As String = "PROJECTINFO"
   
    strSQL = "TRANSFORM MAX(dbo_ProjectDates.dDateForecast) " _
            & "SELECT dbo_ProjectDates.dID " _
            & "FROM dbo_ProjectDates " _
            & "GROUP BY dbo_ProjectDates.dID " _
            & "PIVOT dbo_ProjectDates.dMilestone;"
   
    Set db = CurrentDb
    For t = 0 To db.TableDefs.Count - 1
        If db.TableDefs(t).Name = PROJECTINFO Then
            db.TableDefs.Delete PROJECTINFO                                                    Exit For
        End If
    Next t
    Set rs = db.OpenRecordset(strSQL)
    If rs.RecordCount > 0 Then
        With rs
            .MoveFirst
            Set tbldef = db.CreateTableDef(PROJECTINFO)
            With tbldef
                .Fields.Append .CreateField("cID", dbText, 20)
                .Fields.Append .CreateField("cName", dbText, 255)
                .Fields.Append .CreateField("cDesc", dbMemo)
                For t = 1 To rs.Fields.Count - 1
                    .Fields.Append .CreateField(rs.Fields(t).Name, dbText, 10)
                Next t
            End With
            db.TableDefs.Append tbldef
            db.TableDefs.Refresh
            Set rsDates = db.OpenRecordset(PROJECTINFO)
            While Not .EOF = True
                Set rs1 = db.OpenRecordset("SELECT pname, pdescription FROM dbo_Projectstatus " _
                    & "WHERE pID = '" + .Fields(0) + "'")
                If rs1.RecordCount > 0 Then
                    rs1.MoveFirst
                    rsDates.AddNew
                    rsDates.Fields(0) = .Fields(0)
                    rsDates.Fields(1) = rs1.Fields("pname")
                    rsDates.Fields(2) = rs1.Fields("pdescription")
                    For t = 3 To .Fields.Count - 1
                        rsDates.Fields(t) = .Fields(t - 2)
                    Next t
                    rsDates.Update
                End If
                rs1.Close
                .MoveNext
            Wend
        End With
    End If

Posted in Office (All) | 5 Comments »