Ho intenzione di aggiungere una spiegazione un po 'più lunga e dettagliata dei passi da fare per risolvere questo problema. Mi scuso se è troppo lungo.
Inizierò con la base che hai fornito e lo 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 |
+--------+------+------+------+
I valori nella history.hostid
colonna diventeranno valori y nella tabella pivot. I valori nella history.itemname
colonna diventeranno valori x (per ovvi motivi).
Quando devo risolvere il problema della creazione di una tabella pivot, la affronto utilizzando un processo in tre passaggi (con un quarto passaggio facoltativo):
- selezionare le colonne di interesse, vale a dire valori y e valori x
- estendi la tabella di base con colonne aggiuntive, una per ogni valore x
- raggruppa e aggrega la tabella estesa - un gruppo per ciascun valore y
- (facoltativo) preimpostare la tabella aggregata
Applichiamo questi passaggi al tuo problema e vediamo cosa otteniamo:
Passaggio 1: selezionare le colonne di interesse . Nel risultato desiderato, hostid
fornisce i valori y e itemname
fornisce i valori x .
Passaggio 2: estendere la tabella di base con colonne aggiuntive . In genere è necessaria una colonna per valore x. Ricordiamo che la nostra colonna di valore x è 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 solo aggiunto colonne extra. Nota anche il modello di NULL
s: una riga con itemname = "A"
ha un valore non nullo per la nuova colonna A
e valori nulli per le altre nuove colonne.
Passaggio 3: raggruppare e aggregare 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.) Okay, ci siamo quasi! Dobbiamo solo sbarazzarci di quei brutti NULL
.
Passaggio 4: prettify . Sostituiremo semplicemente i valori null con zero in modo che il set di risultati sia più bello da guardare:
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 tabella pivot bella e carina usando MySQL.
Considerazioni sull'applicazione di questa procedura:
- quale valore usare nelle colonne extra. Ho usato
itemvalue
in questo esempio
- quale valore "neutro" usare nelle colonne extra. Ho usato
NULL
, ma potrebbe anche essere 0
o ""
, a seconda della tua situazione esatta
- quale funzione aggregata usare durante il raggruppamento. Ho usato
sum
, ma count
e max
sono anche spesso usati ( max
è spesso usato quando si costruiscono "oggetti" su una riga che erano stati distribuiti su molte righe)
- utilizzando 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 nella
group by
clausola (e non dimenticarle select
)
Limitazioni note:
- 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 è bella. Per 100, non così bello. Esistono alcune soluzioni con procedure memorizzate che generano una query, ma sono brutte e difficili da ottenere. Al momento non conosco un buon modo per risolvere questo problema quando la tabella pivot deve contenere molte colonne.