Ich werde eine etwas längere und detailliertere Erklärung der Schritte hinzufügen, die zur Lösung dieses Problems zu unternehmen sind. Ich entschuldige mich, wenn es zu lang ist.
Ich beginne mit der Basis, die Sie gegeben haben, und verwende sie, um ein paar Begriffe zu definieren, die ich für den Rest dieses Beitrags verwenden werde. Dies wird die Basistabelle sein :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Das wird unser Ziel sein, die hübsche Pivot-Tabelle :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Werte in history.hostid
Spalte wird zu y-Werten in der Pivottabelle. Werte in history.itemname
Spalte wird zu x-Werten (aus offensichtlichen Gründen).
Wenn ich das Problem der Erstellung einer Pivot-Tabelle lösen muss, gehe ich es mit einem dreistufigen Prozess an (mit einem optionalen vierten Schritt):
- wählen Sie die gewünschten Spalten aus, d. h. y-Werte und x-Werte
- Erweitern Sie die Basistabelle mit zusätzlichen Spalten – eine für jeden x-Wert
- gruppieren und aggregieren Sie die erweiterte Tabelle – eine Gruppe für jeden y-Wert
- (optional) die aggregierte Tabelle verschönern
Lassen Sie uns diese Schritte auf Ihr Problem anwenden und sehen, was wir bekommen:
Schritt 1:Interessante Spalten auswählen . Im gewünschten Ergebnis hostid
liefert die y-Werte und itemname
liefert die x-Werte .
Schritt 2:Erweitern Sie die Basistabelle mit zusätzlichen Spalten . Normalerweise benötigen wir eine Spalte pro x-Wert. Denken Sie daran, dass unsere x-Wert-Spalte itemname
ist :
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 |
+--------+----------+-----------+------+------+------+
Beachten Sie, dass wir die Anzahl der Zeilen nicht geändert haben, sondern nur zusätzliche Spalten hinzugefügt haben. Beachten Sie auch das Muster von NULL
s -- eine Zeile mit itemname = "A"
hat einen Nicht-Null-Wert für die neue Spalte A
und Nullwerte für die anderen neuen Spalten.
Schritt 3:Gruppieren und aggregieren Sie die erweiterte Tabelle . Wir müssen group by hostid
, da es die y-Werte liefert:
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 |
+--------+------+------+------+
(Beachten Sie, dass wir jetzt eine Zeile pro y-Wert haben.) Okay, wir sind fast da! Wir müssen nur diese hässlichen NULL
loswerden s.
Schritt 4:Verschönern . Wir werden einfach alle Nullwerte durch Nullen ersetzen, damit die Ergebnismenge besser anzusehen ist:
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 |
+--------+------+------+------+
Und wir sind fertig – wir haben mit MySQL eine hübsche Pivot-Tabelle erstellt.
Überlegungen zur Anwendung dieses Verfahrens:
- welcher Wert in den zusätzlichen Spalten verwendet werden soll. Ich habe
itemvalue
verwendet in diesem Beispiel - welcher "neutrale" Wert in den zusätzlichen Spalten verwendet werden soll. Ich habe
NULL
verwendet , könnte aber auch0
sein oder""
, abhängig von Ihrer genauen Situation - welche Aggregatfunktion beim Gruppieren verwendet werden soll. Ich habe
sum
verwendet , abercount
undmax
werden auch oft verwendet (max
wird oft verwendet, wenn einzeilige "Objekte" erstellt werden, die über viele Zeilen verteilt wurden) - Mehrere Spalten für y-Werte verwenden. Diese Lösung ist nicht darauf beschränkt, eine einzige Spalte für die y-Werte zu verwenden – stecken Sie einfach die zusätzlichen Spalten in
group by
-Klausel (und vergessen Sie nicht,select
sie)
Bekannte Einschränkungen:
- diese Lösung erlaubt keine n Spalten in der Pivot-Tabelle – jede Pivot-Spalte muss manuell hinzugefügt werden, wenn die Basistabelle erweitert wird. Für 5 oder 10 x-Werte ist diese Lösung also gut. Für 100 nicht so schön. Es gibt einige Lösungen mit gespeicherten Prozeduren, die eine Abfrage generieren, aber sie sind hässlich und schwer richtig zu machen. Ich kenne derzeit keine gute Möglichkeit, dieses Problem zu lösen, wenn die Pivot-Tabelle viele Spalten haben muss.