Aggiungerò una spiegazione un po' più lunga e dettagliata dei passaggi da eseguire per risolvere questo problema. Mi scuso se è troppo lungo.
Inizierò con la base che hai fornito e la userò per definire un paio di termini che userò per il resto di questo post. Questa sarà la tabella di base :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Questo sarà il nostro obiettivo, la bella tabella pivot :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Valori in history.hostid
la colonna diventerà valori y nella tabella pivot. Valori in history.itemname
la colonna diventerà valori x (per ovvi motivi).
Quando devo risolvere il problema della creazione di una tabella pivot, lo affronto utilizzando un processo in tre fasi (con un quarto passaggio opzionale):
- seleziona le colonne di interesse, ovvero valori y e valori x
- estendere la tabella di base con colonne aggiuntive, una per ogni valore x
- raggruppa e aggrega la tabella estesa:un gruppo per ogni valore y
- (opzionale) abbellire la tabella aggregata
Applichiamo questi passaggi al tuo problema e vediamo cosa otteniamo:
Passaggio 1:seleziona le colonne di interesse . Nel risultato desiderato, hostid
fornisce i valori y e itemname
fornisce i valori x .
Passaggio 2:estendi la tabella di base con colonne aggiuntive . In genere abbiamo bisogno di una colonna per valore x. Ricordiamo che la nostra colonna x-value è 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 |
+--------+----------+-----------+------+------+------+
Nota che non abbiamo modificato il numero di righe:abbiamo semplicemente aggiunto colonne extra. Nota anche lo schema di NULL
s -- una riga con itemname = "A"
ha un valore non nullo per la nuova colonna A
e valori null per le altre nuove colonne.
Passaggio 3:raggruppa e aggrega la tabella estesa . Dobbiamo group by hostid
, poiché fornisce i valori 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 |
+--------+------+------+------+
(Nota che ora abbiamo una riga per valore y.) Ok, ci siamo quasi! Dobbiamo solo sbarazzarci di quei brutti NULL
s.
Fase 4:abbellire . Sostituiremo solo qualsiasi valore nullo con zero in modo che il set di risultati sia più bello da vedere:
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 |
+--------+------+------+------+
E abbiamo finito:abbiamo creato una bella tabella pivot utilizzando MySQL.
Considerazioni sull'applicazione di questa procedura:
- quale valore utilizzare nelle colonne extra. Ho usato
itemvalue
in questo esempio - quale valore "neutro" utilizzare nelle colonne extra. Ho usato
NULL
, ma potrebbe anche essere0
o""
, a seconda della tua situazione esatta - quale funzione di aggregazione utilizzare durante il raggruppamento. Ho usato
sum
, macount
emax
sono spesso usati anche (max
viene spesso utilizzato durante la creazione di "oggetti" di una riga che erano stati distribuiti su più righe) - utilizzare più colonne per i valori y. Questa soluzione non si limita all'utilizzo di una singola colonna per i valori y:basta inserire le colonne extra nel
group by
clausola (e non dimenticare diselect
loro)
Limiti noti:
- questa soluzione non consente n colonne nella tabella pivot:ogni colonna pivot deve essere aggiunta manualmente quando si estende la tabella di base. Quindi per 5 o 10 valori x, questa soluzione è buona. Per 100, non così bello. Esistono alcune soluzioni con stored procedure che generano una query, ma sono brutte e difficili da correggere. Al momento non conosco un buon modo per risolvere questo problema quando la tabella pivot deve avere molte colonne.