sql >> Databasteknik >  >> RDS >> Mysql

problem med mysql pivottabell

När du försöker pivotera dynamiskt eller okänt värde, skulle jag alltid föreslå att du börjar med en statisk eller hårdkodad version av frågan först och sedan konverterar den till dynamisk SQL.

MySQL har ingen PIVOT-funktion så du måste använda en aggregatfunktion med ett CASE-uttryck för att få resultatet. Den statiska versionen av koden kommer att likna följande:

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;

Se SQL-fiol med demo .

Om du nu ska ha ett okänt antal keynames som du vill konvertera till kolumner, då måste du använda en förberett uttalande för att generera dynamisk SQL. Koden kommer att likna:

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;

Se SQL-fiol med demo .

En sak att tänka på GROUP_CONCAT funktionen för att skapa kolumnsträngen har en standard maxlängd på 1024, så om du ska ha många tecken i denna sträng kanske du måste ändra sessionsvärdet för group_concat_max_len .

Denna fråga ger ett resultat:

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



  1. Flera datatyper array i PostgreSQL

  2. SQL-referenstabell:Hur man skapar och skriver grundläggande frågor

  3. Autoskapa superanvändare med varje schema django

  4. Fatalt fel:Anrop till odefinierad funktion getsqlvaluestring()