Ik ga een wat langere en meer gedetailleerde uitleg toevoegen van de stappen die moeten worden genomen om dit probleem op te lossen. Mijn excuses als het te lang is.
Ik zal beginnen met de basis die je hebt gegeven en deze gebruiken om een aantal termen te definiëren die ik voor de rest van dit bericht zal gebruiken. Dit wordt de basistabel :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Dit wordt ons doel, de mooie draaitabel :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Waarden in de history.hostid
kolom wordt y-waarden in de draaitabel. Waarden in de history.itemname
kolom wordt x-waarden (om voor de hand liggende redenen).
Wanneer ik het probleem van het maken van een draaitabel moet oplossen, pak ik het aan met behulp van een proces in drie stappen (met een optionele vierde stap):
- selecteer de kolommen van belang, d.w.z. y-waarden en x-waarden
- breid de basistabel uit met extra kolommen -- één voor elke x-waarde
- groepeer en aggregeer de uitgebreide tabel -- één groep voor elke y-waarde
- (optioneel) maak de samengevoegde tabel mooier
Laten we deze stappen toepassen op uw probleem en kijken wat we krijgen:
Stap 1:selecteer interessante kolommen . In het gewenste resultaat, hostid
levert de y-waarden en itemname
levert de x-waarden .
Stap 2:breid de basistabel uit met extra kolommen . We hebben meestal één kolom per x-waarde nodig. Bedenk dat onze x-waarde kolom itemname
is :
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 |
+--------+----------+-----------+------+------+------+
Houd er rekening mee dat we het aantal rijen niet hebben gewijzigd - we hebben alleen extra kolommen toegevoegd. Let ook op het patroon van NULL
s -- een rij met itemname = "A"
heeft een niet-null-waarde voor nieuwe kolom A
, en null-waarden voor de andere nieuwe kolommen.
Stap 3:groepeer en aggregeer de uitgebreide tabel . We moeten group by hostid
, omdat het de y-waarden levert:
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 |
+--------+------+------+------+
(Merk op dat we nu één rij per y-waarde hebben.) Oké, we zijn er bijna! We hoeven alleen maar van die lelijke NULL
af te komen v.
Stap 4:mooier maken . We gaan alle null-waarden vervangen door nullen, zodat de resultatenset mooier is om naar te kijken:
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 |
+--------+------+------+------+
En we zijn klaar -- we hebben een mooie, mooie draaitabel gebouwd met MySQL.
Overwegingen bij het toepassen van deze procedure:
- welke waarde te gebruiken in de extra kolommen. Ik gebruikte
itemvalue
in dit voorbeeld - welke "neutrale" waarde moet worden gebruikt in de extra kolommen. Ik gebruikte
NULL
, maar het kan ook0
. zijn of""
, afhankelijk van uw exacte situatie - welke aggregatiefunctie moet worden gebruikt bij het groeperen. Ik gebruikte
sum
, maarcount
enmax
worden ook vaak gebruikt (max
wordt vaak gebruikt bij het bouwen van "objecten" met één rij die over meerdere rijen waren verspreid) - meerdere kolommen gebruiken voor y-waarden. Deze oplossing is niet beperkt tot het gebruik van een enkele kolom voor de y-waarden -- plug de extra kolommen gewoon in de
group by
clausule (en vergeet niet teselect
hen)
Bekende beperkingen:
- deze oplossing staat geen n kolommen toe in de draaitabel -- elke draaitabel moet handmatig worden toegevoegd bij het uitbreiden van de basistabel. Dus voor 5 of 10 x-waarden is deze oplossing leuk. Voor 100, niet zo leuk. Er zijn enkele oplossingen met opgeslagen procedures die een query genereren, maar ze zijn lelijk en moeilijk om goed te krijgen. Ik weet momenteel geen goede manier om dit probleem op te lossen wanneer de draaitabel veel kolommen moet hebben.