Mysql
 sql >> Database >  >> RDS >> Mysql

problemi con la tabella pivot di MySQL

Quando si tenta di eseguire il pivot di un valore dinamico o sconosciuto, suggerirei sempre di iniziare prima con una versione statica o codificata della query, quindi convertirla in SQL dinamico.

MySQL non ha una funzione PIVOT, quindi dovrai utilizzare una funzione di aggregazione con un'espressione CASE per ottenere il risultato. La versione statica del codice sarà simile alla seguente:

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;

Vedi SQL Fiddle con demo .

Ora, se hai un numero sconosciuto di keynames che desideri convertire in colonne, dovrai utilizzare un dichiarazione preparata per generare SQL dinamico. Il codice sarà simile 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;

Vedi SQL Fiddle con demo .

Una cosa da tenere a mente GROUP_CONCAT la funzione per creare la stringa di colonne ha una lunghezza massima predefinita di 1024, quindi se hai molti caratteri in questa stringa potresti dover modificare il valore della sessione per il group_concat_max_len .

Questa query darà un risultato:

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