保證在列轉換中包含列
Andre指出我最後的回答未能解決顯式PIVOT列列表的一個特徵,即即使數據不包含相應的值,也能列出列。在很多情況下,像David W Fenton評論的那樣,「隨時」生成完整的SQL可能也是一樣。下面是這樣一些模板代碼:
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
就像我的其他的答案,以下查詢允許一個能夠利用在選擇和過濾的標準不同^技術。這種技術不僅可以保證列,還可以更多地控制行^^。
^儘管VBA函數仍然可以在SQL中用於其通常的程度,但Access不允許在使用VBA進行SQL執行期間動態添加新行數據......行必須基於實際的錶行。 (從技術上講,可以使用具有字面值的UNION SELECT來創建行,但這對於大量數據是禁止的,並且不利於任何類型的動態列選擇。)因此,以下技術需要使用輔助表來定義/選擇列值。
第一個查詢應用選擇條件並進行初始分組。如果與我的其他答案相比,這與原始TRANSFORM查詢基本相同 - 只有沒有TRANSFORM和PIVOT。保存並命名此查詢[1初始集合]:
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
接下來創建一個查詢,在所有需要的行值組。在這個例子中,我選擇只包含初始選擇標準中相同的值。 ^^這組數值也可以與之前的選擇標準脫離,不用過濾表或其他查詢。保存並命名此查詢[2個標題]:
SELECT RowSource.City AS City
FROM [1 Initial Aggregate] AS RowSource
GROUP BY RowSource.City
ORDER BY RowSource.City
創建行標題和輔助表[PivotValues]含有列標題的交叉連接。交叉連接從兩個表的每個組合中創建行 - 在Access SQL中,它通過排除所有JOIN關鍵字來完成。保存並命名此查詢[3交叉聯接]:
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months
FROM [2 Row Headings], PivotValues
ORDER BY [2 Row Headings].City, PivotValues.Values;
最後,轉換:通過使用LEFT JOIN,這將包括存在於交叉聯接查詢中的所有列和行。 對於在聯合選擇查詢中缺少數據的列和行對,該列仍將包含(即有保證),其值爲Null。儘管我們已經將最初的查詢分組,但是轉換要求我們重新進行分組 - 可能有點多餘,但對於獲得對最終交叉表結果的理想控制並不是什麼大事。
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
這似乎有點小題大做只是爲了交叉表列動態的,但它可以是值得定義對結果的完全控制一些額外的查詢。 VBA代碼可用於(重新)定義輔助表中的值,從而滿足使用VBA動態指定列的原始問題。
可能有更簡單的方法來做你需要的。你的最終結果是什麼,一份報告?你的標題需要完全改變還是僅僅是有時候有人在那裏,而另一個則不在? – Praesagus