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
itemvaluein questo esempio - quale valore "neutro" utilizzare nelle colonne extra. Ho usato
NULL, ma potrebbe anche essere0o"", a seconda della tua situazione esatta - quale funzione di aggregazione utilizzare durante il raggruppamento. Ho usato
sum, macountemaxsono spesso usati anche (maxviene 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 byclausola (e non dimenticare diselectloro)
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.