Я собираюсь добавить несколько более длинное и подробное объяснение шагов, которые необходимо предпринять для решения этой проблемы. Я прошу прощения, если это слишком долго.
Я начну с базы, которую вы дали, и использую ее, чтобы определить пару терминов, которые я буду использовать для остальной части этого поста. Это будет базовая таблица :
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-значение
- (необязательно) prettify агрегированной таблицы
Давайте применим эти шаги к вашей проблеме и посмотрим, что мы получим:
Шаг 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
s.
Шаг 4: prettify . Мы просто заменим все нулевые значения на нули, поэтому на результат лучше взглянуть:
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 значений х, это решение хорошо. За 100 не очень приятно. Есть некоторые решения с хранимыми процедурами, генерирующими запрос, но они уродливы и их трудно понять. В настоящее время я не знаю хорошего способа решения этой проблемы, когда в сводной таблице должно быть много столбцов.