Я собираюсь добавить несколько более длинное и подробное объяснение шагов, которые необходимо предпринять для решения этой проблемы. Прошу прощения, если это слишком долго.
Я начну с базы, которую вы дали, и воспользуюсь ею, чтобы определить пару терминов, которые я буду использовать в оставшейся части этого сообщения. Это будет базовая таблица :
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
- group и агрегировать расширенную таблицу - по одной группе для каждого значения 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 не очень приятно. Есть некоторые решения с хранимыми процедурами, генерирующими запрос, но они уродливы, и их трудно понять. В настоящее время я не знаю хорошего способа решить эту проблему, когда в сводной таблице должно быть много столбцов.