garanti Inclusion de colonne dans la transformation
Andre a souligné que ma dernière réponse n'a pas réussi à traiter une caractéristique de la liste de colonnes PIVOT explicite, à savoir qu'elle garantit des colonnes même lorsque les données n'incluent pas les valeurs correspondantes. Dans de nombreux cas, il est peut-être tout aussi bien de générer le SQL complet "à la volée" comme l'a commenté David W Fenton. Voici un code de modèle pour le faire:
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
Comme mon autre réponse, les requêtes suivantes permettent d'utiliser diverses techniques^dans la sélection et le filtrage des critères. Non seulement cette technique peut garantir des colonnes, mais cela permet aussi un meilleur contrôle des lignes ^^.^Bien que les fonctions VBA puissent toujours être utilisées dans leur étendue habituelle dans SQL, Access n'autorise pas l'ajout dynamique de nouvelles données de ligne lors de l'exécution SQL à l'aide de VBA ... Les lignes doivent être basées sur des lignes de table réelles. (Techniquement, on peut utiliser un UNION SELECT avec des valeurs littérales pour créer des lignes, mais cela est prohibitif pour beaucoup de données et ne facilite aucune sorte de sélection de colonne dynamique.) Par conséquent, la technique suivante nécessite l'utilisation d'une table auxilliaire/sélection des valeurs de colonne.
La première requête applique des critères de sélection et effectue un regroupement initial. Si vous comparez à mon autre réponse, c'est essentiellement la même chose que la requête TRANSFORM originale - seulement sans TRANSFORM et PIVOT. Enregistrer et nommez cette requête [1 agrégat initial]:
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
Suivant créer une requête que les groupes sur toutes les valeurs de ligne de votre choix. Dans cet exemple, je choisis d'inclure uniquement les mêmes valeurs que les critères de sélection initiaux. ^^ Cet ensemble de valeurs pourrait également être découplé des critères de sélection précédents en le basant sur la table non filtrée ou sur une autre requête. Enregistrer et nommez cette requête [2 têtes Row]:
SELECT RowSource.City AS City
FROM [1 Initial Aggregate] AS RowSource
GROUP BY RowSource.City
ORDER BY RowSource.City
Créer une jointure croisée des têtes de ligne et la table auxiliaire [PivotValues] contenant les têtes de colonne. Une jointure croisée crée des lignes à partir de chaque combinaison des deux tables. Dans Access SQL, elle est effectuée en excluant tous les mots-clés JOIN.Enregistrer et nommez cette requête [3 Cross Rejoignez]:
SELECT [2 Row Headings].City AS City, PivotValues.Values AS Months
FROM [2 Row Headings], PivotValues
ORDER BY [2 Row Headings].City, PivotValues.Values;
Enfin, la transformation: En utilisant LEFT JOIN, cela comprendra toutes les colonnes et les lignes qui existent dans la croix requête de jointure. Pour les paires de colonnes et de lignes qui manquent des données dans la requête de sélection jointe, la colonne sera toujours incluse (c'est-à-dire garantie) avec Null comme valeur. Même si nous avons déjà groupé sur la requête initiale, la transformation nécessite que nous nous regroupions de toute façon - peut-être un peu redondant mais pas un gros problème pour obtenir le contrôle souhaité sur les résultats du tableau croisé final.
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
Cela peut sembler exagéré juste pour rendre les colonnes du tableau croisé dynamique, mais il peut être intéressant de définir quelques requêtes supplémentaires pour un contrôle complet sur les résultats. Le code VBA peut être utilisé pour (re) définir les valeurs dans la table auxiliaire, répondant ainsi à la question initiale d'utilisation de VBA pour spécifier dynamiquement les colonnes.
Il peut être plus facile de faire ce dont vous avez besoin. Quel est votre résultat final, un rapport? Est-ce que vos rubriques doivent changer complètement ou est-ce juste que parfois l'un est là tandis que l'autre ne l'est pas? – Praesagus