Guaranteed column inclusion in the transformation
Andre pointed out that my last answer was not able to solve one of the functions of the explicit list of PIVOT columns, namely that it stores the columns even if the data does not contain the corresponding values. In many cases, it is also possible to generate full SQL on the fly, as David W. Fenton commented. Here are some sample code for this:
Public Function GenerateTransform(valueArray As Variant) As String Dim sIN As String Dim i As Integer, delimit As Boolean If (VarType(valueArray) And vbArray) = vbArray Then For i = LBound(valueArray) To UBound(valueArray) sIN = sIN & IIf(delimit, ",", "") & valueArray(i) delimit = True Next i If Len(sIN) > 0 Then sIN = "IN (" & sIN & ")" End If GenerateTransform = "TRANSFORM ... SELECT ... PIVOT ... " & sIN End Function Public Sub TestGenerateTransform() Dim values(0 To 2) As Integer values(0) = 1 values(1) = 4 values(2) = 12 Debug.Print GenerateTransform(values) Debug.Print GenerateTransform(vbEmpty) 'No column list End Sub
Like my other answer, the following queries allow you to use various methods when selecting and filtering criteria. This method not only guarantees the availability of columns, but also allows more control over ^^ strings.
^ Despite the fact that VBA functions can still be used in their usual volume in SQL, Access does not allow dynamically adding new row data at runtime using SQL VBA ... rows should be based on actual table rows. (Technically, you can use UNION SELECT with literal values ββto create rows, but this is forbidden for large amounts of data and does not facilitate any dynamic selection of columns.) Therefore, the following method requires the use of an auxiliary table to determine / select column values .
The first query applies the selection criteria and the initial grouping. If you compare with my other answer, this is essentially the same as the original TRANSFORM query - only without TRANSFORM and PIVOT. Save and name this query [1 Initial population] :
SELECT Agreement.City, Month([ServiceDate]) AS [Month], Count(Services.ID) AS Schedules FROM Agreement INNER JOIN Services ON Agreement.Account = Services.Account WHERE (Services.Code = "IS") GROUP BY Agreement.City, Month([ServiceDate]) ORDER BY Agreement.City
Then create a query that groups all the values ββof the string. In this example, I prefer to include only the same values ββfrom the original selection criteria. ^^ This set of values ββcan also be separated from previous selection criteria based on an unfiltered table or other query. Save and name this query [2 header lines] :
SELECT RowSource.City AS City FROM [1 Initial Aggregate] AS RowSource GROUP BY RowSource.City ORDER BY RowSource.City
Cross-link row headers and a sub table [PivotValues] containing column headers. A cross join creates rows from each combination of two tables β in Access SQL, this is done with the exception of all JOIN keywords. Save and name this query [3 Cross Join] :
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months FROM [2 Row Headings], PivotValues ORDER BY [2 Row Headings].City, PivotValues.Values;
Finally, the conversion: using the LEFT JOIN, this will include all the columns and rows that exist in the cross join request. For pairs of columns and rows that do not have data in the combined select query, the column will still be included (i.e. guaranteed) with a null value. Despite the fact that we have already grouped the original query, the conversion requires us to re-group anyway - perhaps a little redundant, but not very important to get the desired control over the final results of the crosstab.
TRANSFORM Sum([1 Initial Aggregate].Schedules) AS SumOfSchedules SELECT [3 Cross Join].City AS City FROM [3 Cross Join] LEFT JOIN [1 Initial Aggregate] ON ([3 Cross Join].Months = [1 Initial Aggregate].Month) AND ([3 Cross Join].City = [1 Initial Aggregate].City) GROUP BY [3 Cross Join].City PIVOT [3 Cross Join].Months
This may seem redundant to make the columns of the crosstab dynamic, but for complete control over the results, several additional queries may be required. VBA code can be used to (re) define values ββin a helper table, which satisfies the original question of using VBA to dynamically specify columns.