Vou adicionar uma explicação um pouco mais longa e detalhada das etapas a serem seguidas para resolver esse problema. Peço desculpas se for muito longo.
Vou começar com a base que você deu e usá-la para definir alguns termos que usarei no 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á nosso objetivo, a bela tabela dinâmica :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Valores no
history.hostid
coluna se tornará valores y na tabela dinâmica. Valores no history.itemname
coluna se tornará valores x (por razões óbvias). Quando tenho que resolver o problema de criar uma tabela dinâmica, resolvo isso usando um processo de três etapas (com uma quarta etapa opcional):
- selecione as colunas de interesse, ou seja, valores y e valores x
- estende a tabela base com colunas extras -- uma para cada valor x
- agrupe e agregue a tabela estendida -- um grupo para cada valor y
- (opcional) embelezar a tabela agregada
Vamos aplicar estas etapas ao seu problema e ver o que obtemos:
Etapa 1:selecione as colunas de interesse . No resultado desejado,
hostid
fornece os valores y e itemname
fornece os valores x . Etapa 2:estender 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"
tem 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
, uma vez que fornece os valores de 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
s. Etapa 4:embelezar . Vamos apenas substituir quaisquer valores nulos por zeros para que o conjunto de resultados seja mais agradável de se ver:
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 nós terminamos -- nós construímos uma tabela dinâmica legal 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 ser0
ou""
, dependendo da sua situação exata - qual função de agregação usar ao agrupar. Eu usei
sum
, mascount
emax
também são frequentemente usados (max
é frequentemente usado ao construir "objetos" de uma linha que foram espalhados por muitas linhas) - usando várias colunas para valores y. Esta solução não se limita a usar uma única coluna para os valores y -- basta conectar as colunas extras ao
group by
cláusula (e não se esqueça deselect
eles)
Limitações conhecidas:
- esta solução não permite n colunas na tabela dinâmica -- cada coluna dinâmica precisa ser adicionada manualmente ao estender a tabela base. Então, para 5 ou 10 valores x, esta solução é boa. Por 100, não é tão bom. Existem algumas soluções com procedimentos armazenados gerando uma consulta, mas são feias e difíceis de acertar. Atualmente, não conheço uma boa maneira de resolver esse problema quando a tabela dinâmica precisa ter muitas colunas.