Mysql
 sql >> Base de données >  >> RDS >> Mysql

MySQL - Lignes aux colonnes

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) :

  1. sélectionnez les colonnes qui vous intéressent, c'est-à-dire les valeurs y et valeurs x
  2. étendre la table de base avec des colonnes supplémentaires :une pour chaque valeur x
  3. regrouper et agréger le tableau étendu -- un groupe pour chaque valeur y
  4. (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 être 0 ou "" , selon votre situation exacte
  • quelle fonction d'agrégation utiliser lors du regroupement ? J'ai utilisé sum , mais count et max 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 de select 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.