Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Probleme mit mysql-Pivot-Tabelle

Wenn Sie versuchen, dynamische oder unbekannte Werte zu pivotieren, würde ich immer vorschlagen, dass Sie zuerst mit einer statischen oder hartcodierten Version der Abfrage beginnen und sie dann in dynamisches SQL konvertieren.

MySQL hat keine PIVOT-Funktion, daher müssen Sie eine Aggregatfunktion mit einem CASE-Ausdruck verwenden, um das Ergebnis zu erhalten. Die statische Version des Codes sieht etwa so aus:

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;

Siehe SQL-Fiddle mit Demo .

Nun, wenn Sie eine unbekannte Anzahl von keynames haben werden die Sie in Spalten umwandeln möchten, müssen Sie einen vorbereitete Erklärung um dynamisches SQL zu generieren. Der Code sieht ähnlich aus wie:

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;

Siehe SQL-Fiddle mit Demo .

Eine Sache, die Sie im Hinterkopf behalten sollten, ist der GROUP_CONCAT Die Funktion zum Erstellen der Spaltenzeichenfolge hat eine standardmäßige maximale Länge von 1024. Wenn Sie also viele Zeichen in dieser Zeichenfolge haben möchten, müssen Sie möglicherweise den Sitzungswert für group_concat_max_len ändern .

Diese Abfrage liefert ein Ergebnis:

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