2017-10-11 14 views
1

Je pense que j'essaie de faire quelque chose qui ne peut pas être fait. J'essaie de créer un tableau croisé dynamique, en faisant simultanément deux pivots en agrégeant deux colonnes différentes. J'ai créé un exemple très simplifié pour rendre le point plus compréhensible.créer un tableau croisé dynamique avec des agrégats sans jointure

CREATE TABLE two_aggregate_pivot (
    ID INT, 
    category CHAR(1), 
    value INT 
) 

INSERT INTO dbo.two_aggregate_pivot 
    (ID, category, value) 
VALUES (1, 'A', 100), 
     (1, 'B', 97), 
     (1, 'D', NULL), 
     (2, 'A', 86), 
     (2, 'C', 83), 
     (2, 'D', 81)    

Je peux pivoter pour obtenir le nombre des catégories comme suit:

SELECT piv1.ID, 
     [A] AS cat_A, 
     [B] AS cat_B, 
     [C] AS cat_C, 
     [D] AS cat_D 
FROM 
(SELECT ID, category FROM dbo.two_aggregate_pivot) SRC 
PIVOT 
(
    COUNT(category) 
    FOR category IN ([A],[B],[C],[D]) 
) piv1 

Et je ce que je veux.

ID cat_A cat_B cat_C cat_D 
1 1  1  0  1 
2 1  0  1  1 

Alors aussi je peux écrire une requête totalement séparée, ajoutez la colonne de valeur dans la sélection de la source, et d'agrégats de MAX (valeur) à la place, et d'obtenir un pivot de valeurs max.

ID val_A val_B val_C val_D 
1 100  97  NULL NULL 
2 86  NULL 83  81 

Mais ce que je n'arrive pas à comprendre, c'est comment les obtenir tous les deux.

ID cat_A cat_B cat_C cat_D val_A val_B val_C val_D 
1 1  1  0  1  100  97  NULL NULL 
2 1  0  1  1  86  NULL 83  81 

J'ai vu des exemples ici sur stackoverflow en utilisant les instructions CASE pour vérifier IS NOT NULL, mais cela ne fonctionne pas pour moi, je ne pense pas non, car je peux avoir les deux valeurs et les valeurs manquantes existantes qui sont vraiment NUL. Je peux créer deux CTE, un avec chaque PIVOT, puis les JOINs. Cela me donne la table que je veux, mais elle force deux fois l'indexation en cluster de la table, et bien sûr l'opérateur de jointure. La table est assez volumineuse et les performances sont importantes. Je souhaite donc trouver un moyen de faire les deux pivots dans la même analyse d'index en cluster.

Est-ce encore possible?

Répondre

1

Peut-être un CROSS APPLY pour unpivot vos données. Je devrais ajouter, ce serait une petite affaire d'aller dynamique.

Exemple

Select * 
From (
      Select ID 
        ,B.* 
      From two_aggregate_pivot A 
      Cross Apply (values ('cat_'+category ,1) 
           ,('val_'+category ,value) 
         ) B (Item,Value) 
     ) src 
    Pivot (sum(value) for item in ([cat_A],[cat_B],[cat_C],[cat_D],[val_A],[val_B],[val_C],[val_D])) pvt 

Retours

ID cat_A cat_B cat_C cat_D val_A val_B val_C val_D 
1 1  1  NULL 1  100  97  NULL NULL 
2 1  NULL 1  1  86  NULL 83  81 
+0

Désolé pour le long délai répondre à cette. J'ai été déconner avec cette requête en essayant de comprendre comment fonctionne la magie. En regardant la requête interne aide. Je pense que je peux modifier cela pour fonctionner dans mon cas, et je vais modifier ce commentaire pour indiquer comment il fonctionne par rapport à la jonction des deux pivots. –

+0

@RobertSievers Toutes mes excuses pour la réponse tardive. J'ai été retiré. Faites-moi savoir si je peux aider –

+0

Eh bien, voici les résultats. La méthode PIVIOT JOIN est 30% moins efficace que la méthode CROSS APPLY, mesurée par le coût du sous-arbre d'exécution. Effectivement, le CROSS APPLY a la moitié des lectures logiques, mais cela prend deux fois le temps CPU. La durée réelle sort presque exactement identique. Donc, si vous avez un disque rapide, utilisez la méthode de jointure à deux pivots. Si vous avez un disque lent et un processeur rapide, utilisez le CROSS APPLY. –