Vou adicionar uma explicação um pouco mais longa e detalhada dos passos a serem tomados para resolver esse problema. Peço desculpas se for muito longo.
Começarei com a base que você forneceu e a utilizará para definir alguns termos que utilizarei para o restante deste post. Esta será a tabela base :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Este será o nosso objetivo, a bonita tabela dinâmica :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Os valores na history.hostid
coluna se tornarão valores y na tabela dinâmica. Os valores na history.itemname
coluna se tornarão valores x (por razões óbvias).
Quando tenho que resolver o problema de criar uma tabela dinâmica, resolvo-a usando um processo de três etapas (com uma quarta etapa opcional):
- seleccionar as colunas de interesse, ou seja, valores de y e x-valores
- estenda a tabela base com colunas extras - uma para cada valor x
- agrupar e agregar a tabela estendida - um grupo para cada valor y
- (opcional) pré-definir a tabela agregada
Vamos aplicar estas etapas ao seu problema e ver o que temos:
Etapa 1: selecione colunas de interesse . No resultado desejado, hostid
fornece os valores de y e itemname
fornece os valores de x .
Etapa 2: estenda a tabela base com colunas extras . Normalmente, precisamos de uma coluna por valor x. Lembre-se de que nossa coluna de valor 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 |
+--------+----------+-----------+------+------+------+
Observe que não alteramos o número de linhas - apenas adicionamos colunas extras. Observe também o padrão de NULL
s - uma linha com itemname = "A"
um valor não nulo para a nova coluna A
e valores nulos para as outras novas colunas.
Etapa 3: agrupe e agregue a tabela estendida . Precisamos group by hostid
, pois fornece os valores 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 |
+--------+------+------+------+
(Observe que agora temos uma linha por valor y). Ok, estamos quase lá! Nós só precisamos nos livrar daqueles feios NULL
.
Etapa 4: prettify . Vamos substituir todos os valores nulos por zeros, para que o conjunto de resultados seja melhor:
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 |
+--------+------+------+------+
E pronto - nós construímos uma tabela dinâmica bonita e bonita usando o MySQL.
Considerações ao aplicar este procedimento:
- qual valor usar nas colunas extras. Eu usei
itemvalue
neste exemplo
- qual valor "neutro" usar nas colunas extras. Eu usei
NULL
, mas também pode ser 0
ou ""
, dependendo da sua situação exata
- qual função agregada usar ao agrupar. Eu costumava
sum
, mas count
e max
também são usados frequentemente (max
é frequentemente utilizado na construção de uma linha "objetos" que tinham sido espalhados por várias linhas)
- usando várias colunas para valores y. Essa solução não se limita ao uso de uma única coluna para os valores y - basta conectar as colunas extras à
group by
cláusula (e não se esqueça select
delas)
Limitações conhecidas:
- essa solução não permite n colunas na tabela dinâmica - cada coluna dinâmica precisa ser adicionada manualmente ao estender a tabela base. Portanto, para 5 ou 10 valores x, esta solução é boa. Por 100, não é tão legal. Existem algumas soluções com procedimentos armazenados que geram uma consulta, mas são feias e difíceis de corrigir. Atualmente, não conheço uma boa maneira de resolver esse problema quando a tabela dinâmica precisa ter muitas colunas.