sql >> Base de Datos >  >> RDS >> Mysql

problemas con la tabla dinámica mysql

Cuando intenta pivotar un valor dinámico o desconocido, siempre le sugiero que primero comience con una versión estática o codificada de la consulta y luego la convierta a SQL dinámico.

MySQL no tiene una función PIVOT, por lo que deberá usar una función agregada con una expresión CASE para obtener el resultado. La versión estática del código será similar a la siguiente:

select t.id teamid, 
  t.name teamname, 
  p.id processid, 
  p.name processname,
  max(case when pd.keyname = 'shape' then tpd.value end) shape,
  max(case when pd.keyname = 'vegetable' then tpd.value end) vegetable,
  max(case when pd.keyname = 'fruit' then tpd.value end) fruit,
  max(case when pd.keyname = 'animal' then tpd.value end) animal
from teams t
inner join teamprocesses tp
  on t.id = tp.teamid
inner join TeamProcessDetails tpd
  on tp.id = tpd.teamProcessId
inner join processes p
  on tp.processid = p.id
inner join processdetails pd
  on p.id = pd.processid
  and tpd.processDetailsid = pd.id
group by t.id, t.name, p.id, p.name;

Consulte SQL Fiddle con demostración .

Ahora, si va a tener un número desconocido de keynames que desea convertir en columnas, deberá usar un declaración preparada para generar SQL dinámico. El código será similar a:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when pd.keyname = ''',
      keyname,
      ''' then tpd.value end) AS ',
      replace(keyname, ' ', '')
    )
  ) INTO @sql
from ProcessDetails;

SET @sql 
    = CONCAT('SELECT t.id teamid, 
                t.name teamname, 
                p.id processid, 
                p.name processname, ', @sql, ' 
              from teams t
              inner join teamprocesses tp
                on t.id = tp.teamid
              inner join TeamProcessDetails tpd
                on tp.id = tpd.teamProcessId
              inner join processes p
                on tp.processid = p.id
              inner join processdetails pd
                on p.id = pd.processid
                and tpd.processDetailsid = pd.id
              group by t.id, t.name, p.id, p.name;');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Consulte SQL Fiddle con demostración .

Una cosa a tener en cuenta es el GROUP_CONCAT La función para crear la cadena de columnas tiene una longitud máxima predeterminada de 1024, por lo que si va a tener muchos caracteres en esta cadena, es posible que deba modificar el valor de la sesión para group_concat_max_len .

Esta consulta dará un resultado:

| TEAMID | TEAMNAME | PROCESSID | PROCESSNAME |  SHAPE | VEGETABLE |  FRUIT | ANIMAL |
|      1 |    teamA |         1 |    processA | circle |    carrot |  apple | (null) |
|      1 |    teamA |         2 |    processB | (null) |    (null) | (null) |    dog |