Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

problema com tabela dinâmica mysql


Quando você está tentando dinamizar um valor dinâmico ou desconhecido, eu sempre sugiro que você comece com uma versão estática ou codificada primeiro da consulta e depois a converta em SQL dinâmico.

O MySQL não tem uma função PIVOT, então você precisará usar uma função agregada com uma expressão CASE para obter o resultado. A versão estática do código será semelhante à seguinte:
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 with Demo .

Agora, se você tiver um número desconhecido de keynames que você deseja converter em colunas, então você precisará usar um declaração preparada para gerar SQL dinâmico. O código será semelhante 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 with Demo .

Uma coisa a ter em mente é o GROUP_CONCAT A função para criar a string de colunas tem um comprimento máximo padrão de 1024, portanto, se você tiver muitos caracteres nessa string, talvez seja necessário alterar o valor da sessão para o group_concat_max_len .

Esta consulta dará um 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 |