Voy a agregar una explicación un poco más larga y más detallada de los pasos a seguir para resolver este problema. Pido disculpas si es demasiado largo.
Comenzaré con la base que has dado y la usaré para definir un par de términos que usaré para el resto de esta publicación. Esta será la tabla base :
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
Este será nuestro objetivo, la bonita tabla dinámica :
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
Los valores en la history.hostid
columna se convertirán en valores y en la tabla dinámica. Los valores en la history.itemname
columna se convertirán en valores x (por razones obvias).
Cuando tengo que resolver el problema de crear una tabla dinámica, lo abordo mediante un proceso de tres pasos (con un cuarto paso opcional):
- seleccionar las columnas de interés, es decir , valores y y valores x
- extienda la tabla base con columnas adicionales, una para cada valor de x
- agrupe y agregue la tabla extendida: un grupo para cada valor de y
- (opcional) prettify la tabla agregada
Apliquemos estos pasos a su problema y veamos qué obtenemos:
Paso 1: seleccione columnas de interés . En el resultado deseado, hostid
proporciona los valores y y itemname
proporciona los valores x .
Paso 2: extienda la tabla base con columnas adicionales . Por lo general, necesitamos una columna por valor de x. Recuerde que nuestra columna de valor x es 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 |
+--------+----------+-----------+------+------+------+
Tenga en cuenta que no cambiamos el número de filas, solo agregamos columnas adicionales. También tenga en cuenta el patrón de NULL
s: una fila con itemname = "A"
tiene un valor no nulo para la nueva columna A
y valores nulos para las otras columnas nuevas.
Paso 3: agrupe y agregue la tabla extendida . Necesitamos group by hostid
, ya que proporciona los 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 |
+--------+------+------+------+
(Tenga en cuenta que ahora tenemos una fila por valor de y). Bien, ¡ya casi llegamos! Solo tenemos que deshacernos de esos feos NULL
.
Paso 4: prettify . Simplemente vamos a reemplazar cualquier valor nulo con ceros para que el conjunto de resultados sea más agradable de 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 |
+--------+------+------+------+
Y hemos terminado: hemos creado una tabla dinámica agradable y bonita con MySQL.
Consideraciones al aplicar este procedimiento:
- qué valor usar en las columnas adicionales. Yo usé
itemvalue
en este ejemplo
- qué valor "neutral" usar en las columnas adicionales. Solía
NULL
, pero también podría ser 0
o ""
, dependiendo de tu situación exacta
- qué función agregada usar al agrupar. Solía
sum
, pero count
y max
también se utilizan a menudo ( max
se utiliza a menudo en la construcción de una sola hilera "objetos" que habían sido repartidos en muchas filas)
- usando múltiples columnas para valores de y. Esta solución no se limita al uso de una sola columna para los valores y, simplemente conecte las columnas adicionales a la
group by
cláusula (y no se olvide de select
ellas)
Limitaciones conocidas:
- Esta solución no permite n columnas en la tabla dinámica: cada columna dinámica debe agregarse manualmente al extender la tabla base. Entonces, para 5 o 10 valores x, esta solución es buena. Por 100, no tan agradable. Hay algunas soluciones con procedimientos almacenados que generan una consulta, pero son feas y difíciles de corregir. Actualmente no conozco una buena manera de resolver este problema cuando la tabla dinámica necesita tener muchas columnas.