Je vais ajouter une explication un peu plus longue et plus détaillée des étapes à suivre pour résoudre ce problème. Je m'excuse si c'est trop long.
Je vais commencer par la base que vous avez donnée et l'utiliser pour définir quelques termes que j'utiliserai pour le reste de cet article. Ce sera la table de base :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Ce sera notre objectif, le joli tableau croisé dynamique :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Valeurs dans history.hostid
la colonne deviendra valeurs y dans le tableau croisé dynamique. Valeurs dans history.itemname
la colonne deviendra valeurs x (pour des raisons évidentes).
Lorsque je dois résoudre le problème de la création d'un tableau croisé dynamique, je l'aborde en trois étapes (avec une quatrième étape facultative) :
- sélectionnez les colonnes qui vous intéressent, c'est-à-dire les valeurs y et valeurs x
- étendre la table de base avec des colonnes supplémentaires :une pour chaque valeur x
- regrouper et agréger le tableau étendu -- un groupe pour chaque valeur y
- (facultatif) embellir le tableau agrégé
Appliquons ces étapes à votre problème et voyons ce que nous obtenons :
Étape 1 :sélectionnez les colonnes qui vous intéressent . Dans le résultat souhaité, hostid
fournit les valeurs y et itemname
fournit les valeurs x .
Étape 2 :étendez le tableau de base avec des colonnes supplémentaires . Nous avons généralement besoin d'une colonne par valeur x. Rappelez-vous que notre colonne de valeur x est itemname
:
create view history_extended as (
select
history.*,
case when itemname = "A" then itemvalue end as A,
case when itemname = "B" then itemvalue end as B,
case when itemname = "C" then itemvalue end as C
from history
);
select * from history_extended;
+--------+----------+-----------+------+------+------+
| hostid | itemname | itemvalue | A | B | C |
+--------+----------+-----------+------+------+------+
| 1 | A | 10 | 10 | NULL | NULL |
| 1 | B | 3 | NULL | 3 | NULL |
| 2 | A | 9 | 9 | NULL | NULL |
| 2 | C | 40 | NULL | NULL | 40 |
+--------+----------+-----------+------+------+------+
Notez que nous n'avons pas modifié le nombre de lignes ; nous avons simplement ajouté des colonnes supplémentaires. Notez également le modèle de NULL
s -- une ligne avec itemname = "A"
a une valeur non nulle pour la nouvelle colonne A
, et des valeurs nulles pour les autres nouvelles colonnes.
Étape 3 :regrouper et agréger le tableau étendu . Nous devons group by hostid
, puisqu'il fournit les valeurs y :
create view history_itemvalue_pivot as (
select
hostid,
sum(A) as A,
sum(B) as B,
sum(C) as C
from history_extended
group by hostid
);
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | NULL |
| 2 | 9 | NULL | 40 |
+--------+------+------+------+
(Notez que nous avons maintenant une ligne par valeur y.) Bon, on y est presque ! Nous avons juste besoin de nous débarrasser de ces vilains NULL
s.
Étape 4 :embellir . Nous allons simplement remplacer toutes les valeurs nulles par des zéros afin que le jeu de résultats soit plus agréable à regarder :
create view history_itemvalue_pivot_pretty as (
select
hostid,
coalesce(A, 0) as A,
coalesce(B, 0) as B,
coalesce(C, 0) as C
from history_itemvalue_pivot
);
select * from history_itemvalue_pivot_pretty;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Et nous avons terminé :nous avons créé un joli tableau croisé dynamique à l'aide de MySQL.
Considérations lors de l'application de cette procédure :
- quelle valeur utiliser dans les colonnes supplémentaires. J'ai utilisé
itemvalue
dans cet exemple - quelle valeur "neutre" utiliser dans les colonnes supplémentaires. J'ai utilisé
NULL
, mais cela peut aussi être0
ou""
, selon votre situation exacte - quelle fonction d'agrégation utiliser lors du regroupement ? J'ai utilisé
sum
, maiscount
etmax
sont aussi souvent utilisés (max
est souvent utilisé lors de la construction d'"objets" d'une seule ligne qui ont été répartis sur plusieurs lignes) - utiliser plusieurs colonnes pour les valeurs y. Cette solution n'est pas limitée à l'utilisation d'une seule colonne pour les valeurs y - il suffit de brancher les colonnes supplémentaires dans le
group by
clause (et n'oubliez pas deselect
eux)
Limitations connues :
- cette solution n'autorise pas n colonnes dans le tableau croisé dynamique :chaque colonne pivot doit être ajoutée manuellement lors de l'extension du tableau de base. Donc pour 5 ou 10 valeurs x, cette solution est sympa. Pour 100, pas si agréable. Il existe des solutions avec des procédures stockées générant une requête, mais elles sont laides et difficiles à maîtriser. Je ne connais actuellement aucun moyen efficace de résoudre ce problème lorsque le tableau croisé dynamique doit comporter de nombreuses colonnes.