Ще добавя малко по-дълго и по-подробно обяснение на стъпките, които трябва да предприемете за решаване на този проблем. Извинявам се, ако е твърде дълго.
Ще започна с базата, която сте дали и ще я използвам, за да дефинирам няколко термина, които ще използвам до края на тази публикация. Това ще бъде основната таблица :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Това ще бъде нашата цел, красивата опорна маса :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Стойности в history.hostid
колоната ще стане y-стойности в централната таблица. Стойности в history.itemname
колоната ще се превърне в x-стойности (по очевидни причини).
Когато трябва да реша проблема със създаването на въртяща се таблица, се справям с него с помощта на процес от три стъпки (с незадължителна четвърта стъпка):
- изберете колоните, които представляват интерес, т.е. y-стойности и x-стойности
- разширете основната таблица с допълнителни колони – по една за всяка x-стойност
- групирайте и агрегирайте разширената таблица – една група за всяка y-стойност
- (по избор) украсете обобщената таблица
Нека приложим тези стъпки към вашия проблем и да видим какво получаваме:
Стъпка 1:изберете колони, представляващи интерес . В желания резултат hostid
предоставя y-стойности и itemname
предоставя x-стойности .
Стъпка 2:разширете основната таблица с допълнителни колони . Обикновено се нуждаем от една колона на x-стойност. Припомнете си, че нашата колона с 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 |
+--------+----------+-----------+------+------+------+
Имайте предвид, че не сме променили броя на редовете - просто добавихме допълнителни колони. Обърнете внимание и на модела на NULL
s -- ред с itemname = "A"
има ненулева стойност за нова колона A
и нулеви стойности за другите нови колони.
Стъпка 3:групирайте и обобщете разширената таблица . Трябва да group by hostid
, тъй като предоставя 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 |
+--------+------+------+------+
(Обърнете внимание, че вече имаме един ред на y-стойност.) Добре, почти сме там! Просто трябва да се отървем от тези грозни NULL
с.
Стъпка 4:украсете . Просто ще заменим всички нулеви стойности с нули, така че наборът от резултати да е по-приятен за гледане:
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 |
+--------+------+------+------+
И сме готови -- изградихме хубава, хубава централна таблица, използвайки MySQL.
Съображения при прилагането на тази процедура:
- каква стойност да използвате в допълнителните колони. Използвах
itemvalue
в този пример - каква „неутрална“ стойност да използвате в допълнителните колони. Използвах
NULL
, но може да бъде и0
или""
, в зависимост от вашата точна ситуация - каква обобщена функция да използвате при групиране. Използвах
sum
, ноcount
иmax
също често се използват (max
често се използва при изграждане на едноредови „обекти“, които са били разпределени в много редове) - използване на множество колони за y-стойности. Това решение не се ограничава до използването на една колона за y-стойностите - просто включете допълнителните колони в
group by
клауза (и не забравяйте даselect
тях)
Известни ограничения:
- това решение не позволява n колони в обобщената таблица – всяка опорна колона трябва да бъде добавена ръчно при разширяване на основната таблица. Така че за 5 или 10 x-стойности това решение е хубаво. За 100 не е толкова хубаво. Има някои решения със съхранени процедури, генериращи заявка, но те са грозни и трудни за оправяне. Понастоящем не знам добър начин за разрешаване на този проблем, когато централната таблица трябва да има много колони.