Jag kommer att lägga till en något längre och mer detaljerad förklaring av stegen för att lösa detta problem. Jag ber om ursäkt om det är för långt.
Jag börjar med basen du har gett och använder den för att definiera ett par termer som jag kommer att använda för resten av det här inlägget. Detta kommer att vara bastabellen :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Detta kommer att vara vårt mål, den sköna pivottabellen :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Värden i history.hostid
kolumnen blir y-värden i pivottabellen. Värden i history.itemname
kolumnen blir x-värden (av uppenbara skäl).
När jag måste lösa problemet med att skapa en pivottabell, tar jag itu med det med en trestegsprocess (med ett valfritt fjärde steg):
- välj kolumnerna av intresse, dvs. y-värden och x-värden
- utöka bastabellen med extra kolumner -- en för varje x-värde
- gruppera och aggregera den utökade tabellen -- en grupp för varje y-värde
- (valfritt) förfina den aggregerade tabellen
Låt oss tillämpa dessa steg på ditt problem och se vad vi får:
Steg 1:välj kolumner av intresse . I önskat resultat, hostid
ger y-värdena och itemname
tillhandahåller x-värden .
Steg 2:utöka bastabellen med extra kolumner . Vi behöver vanligtvis en kolumn per x-värde. Kom ihåg att vår x-värdeskolumn är 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 |
+--------+----------+-----------+------+------+------+
Observera att vi inte ändrade antalet rader – vi lade bara till extra kolumner. Notera också mönstret för NULL
s -- en rad med itemname = "A"
har ett icke-nullvärde för ny kolumn A
, och null-värden för de andra nya kolumnerna.
Steg 3:gruppera och aggregera den utökade tabellen . Vi måste group by hostid
eftersom det ger y-värdena:
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 |
+--------+------+------+------+
(Observera att vi nu har en rad per y-värde.) Okej, vi är nästan framme! Vi behöver bara bli av med de där fula NULL
s.
Steg 4:försköna . Vi kommer bara att ersätta alla nollvärden med nollor så att resultatuppsättningen är snyggare att titta på:
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 |
+--------+------+------+------+
Och vi är klara -- vi har byggt en snygg, vacker pivottabell med MySQL.
Att tänka på när du tillämpar denna procedur:
- vilket värde som ska användas i de extra kolumnerna. Jag använde
itemvalue
i det här exemplet - vilket "neutralt" värde som ska användas i de extra kolumnerna. Jag använde
NULL
, men det kan också vara0
eller""
, beroende på din exakta situation - vilken aggregatfunktion som ska användas vid gruppering. Jag använde
sum
, mencount
ochmax
används också ofta (max
används ofta när man bygger enrads "objekt" som hade spridits över många rader) - använder flera kolumner för y-värden. Den här lösningen är inte begränsad till att använda en enda kolumn för y-värdena – anslut bara de extra kolumnerna till
group by
klausul (och glöm inte attselect
dem)
Kända begränsningar:
- den här lösningen tillåter inte n kolumner i pivottabellen -- varje pivotkolumn måste läggas till manuellt när bastabellen utökas. Så för 5 eller 10 x-värden är den här lösningen bra. För 100, inte så trevligt. Det finns vissa lösningar med lagrade procedurer som genererar en fråga, men de är fula och svåra att få rätt. Jag känner för närvarande inte till ett bra sätt att lösa det här problemet när pivottabellen behöver ha många kolumner.