sql >> Databasteknik >  >> RDS >> Mysql

PHP och Mysql-fråga, använd PHP för att konvertera rader till kolumner

Det är möjligt att få resultatet med en SQL-fråga, men det är inte trivialt.

Men innan du går den vägen rekommenderar jag att du överväger ett annat tillvägagångssätt.

Eftersom frågan returnerar en relativt liten uppsättning rader kan du istället hämta hela resultatuppsättningen i PHP som en tvådimensionell array.

Betrakta ett ganska enkelt fall, som en illustration:

SELECT foo, fee, fi, fo, fum
  FROM mytable 
 ORDER BY foo

foo fee fi  fo  fum
--- --- --- --- ---
ABC   2   3   5   7
DEF  11  13  17  19

Vi skulle kunna göra en fetchAll och få en tvådimensionell array, sedan loopa genom arrayen och hämta värdena kolumnvis, snarare än radvis. Ett alternativ är att omvandla arrayen vi tar emot till en ny array som ser ut så här:

bar  ABC  DEF
---  ---  ---
fee    2   11
fi     3   13
fo     5   17
fum    7   19

Det är egentligen inte nödvändigt att göra omvandlingen, du kan gå den ursprungliga arrayen. Men att separera omvandlingen som ett separat steg skulle förmodligen göra din kod lite lättare när du faktiskt kommer till att generera utdata på sidan. (Det verkar vara ett tillräckligt vanligt problem att någon förmodligen har skrivit en funktion som gör den arraytransformation du vill ha. Jag tror inte att det finns en PHP-inbyggd som gör det.

rubriker:

array { [0]=>'bar'  [1]=>'ABC'  [2]=>'DEF' }

rader:

array {
  [0]=>array { [0]=>'fee'   [1]=>'2'  [2]=>'11' }
  [1]=>array { [0]=>'fi'    [1]=>'3'  [2]=>'13' }
  [2]=>array { [0]=>'fo'    [1]=>'5'  [2]=>'17' }
  [3]=>array { [0]=>'fum'   [1]=>'7'  [2]=>'19' }
}

För en liten uppsättning rader som du har, skulle jag välja att göra detta i PHP snarare än i SQL.

Men du frågade hur man gör det i SQL. Som jag sa tidigare, det är inte trivialt.

SQL kräver att SELECT-satsen definierar varje kolumn som ska returneras; antalet och typerna av kolumnerna kan inte vara dynamiska när satsen körs.

Om vi ​​bygger en annan fråga (förutom den ursprungliga frågan) som definierar kolumnerna och returnerar de rader som vi förväntar oss returnerade med platshållare för värdena, är vi halvvägs där. Allt som återstår är att göra en yttre koppling till raderna som returneras av den ursprungliga frågan, och villkorligt returnera kolumnvärdena på lämpliga rader.

Det här tillvägagångssättet fungerar om du har en fördefinierad uppsättning rader och kolumner som vi behöver returneras, särskilt när den ursprungliga radkällan är gles, och vi måste generera de "saknade" raderna. (Till exempel att få antalet beställda produkter och det finns många saknade rader, det finns inte ett bra sätt att generera de saknade raderna.

Till exempel:

SELECT r.bar
     , '' AS `ABC`
     , '' AS `DEF`
  FROM ( SELECT 'fee' AS bar
          UNION ALL SELECT 'fi'
          UNION ALL SELECT 'fo'
          UNION ALL SELECT 'fum'
       ) r
 GROUP BY r.bar

Det kommer att returnera:

 bar  ABC  DEF
 ---  ---  ---
 fee
 fi
 fo
 fum

Så det får oss alla kolumner definierade och alla rader vi vill returnera. Den första kolumnen är ifylld. Den frågan behöver egentligen inte GROUP BY ännu, men vi kommer att behöva den när vi matchar raderna i den "riktiga" källresultatuppsättningen.

"Knepet" nu är att matcha raderna från vår källa och returnera värdet från en kolumn baserat på lämpliga villkor.

Vad vi kommer att generera är i huvudsak en resultatuppsättning som ser ut så här:

bar  foo  ABC  DEF
---  ---  ---  ---
fee  ABC    2
fee  DEF        11
fi   ABC    3
fi   DEF        13
fo   ABC    5
fo   DEF        15
fum  ABC    7
fum  DEF        17

Sedan ska vi "komprimera" raderna genom att ta bort foo-kolumnen från resultatuppsättningen och göra en GROUP BY på bar . Vi kommer att använda en aggregatfunktion (antingen MAX eller SUM) och dra nytta av hanteringen de gör med NULL-värden, för att producera ett resultat som detta:

bar  foo  ABC  DEF
---  ---  ---  ---
fee         2   11
fi          3   13
fo          5   15
fum         7   17

Använder denna ganska svårhanterliga SQL:

SELECT r.bar
     , MAX(CASE WHEN t.foo = 'ABC' THEN CASE r.bar 
         WHEN 'fee' THEN t.fee 
         WHEN 'fi'  THEN t.fi
         WHEN 'fo'  THEN t.fo
         WHEN 'fum' THEN t.fum
       END END) AS 'ABC'
     , MAX(CASE WHEN t.foo = 'DEF' THEN CASE r.bar 
         WHEN 'fee' THEN t.fee 
         WHEN 'fi'  THEN t.fi
         WHEN 'fo'  THEN t.fo
         WHEN 'fum' THEN t.fum
       END END) AS 'DEF'
  FROM ( SELECT 'foo' AS col
          UNION ALL SELECT 'fee'
          UNION ALL SELECT 'fi'
          UNION ALL SELECT 'fo'
          UNION ALL SELECT 'fum'
       ) r
 CROSS
  JOIN mysource t
 GROUP BY r.bar

Observera att mysource i frågan ovan kan ersättas med en inline-vy, linda parens runt en lämplig fråga som returnerar de rader vi vill ha.

Den infogade vyn alias som r är vår källa för att returnera de rader vi vill returnera.

Uttrycken i SELECT-listan gör de villkorliga testerna för att välja ut rätt värden för varje kolumn i varje rad.

Med tanke på det vanliga mönstret för CASE-satserna är det möjligt att använda lite SQL för att generera frågan, men det måste göras som ett separat steg. Utdata från den SQL kan användas för att skapa den faktiska fråga vi behöver.

I ditt fall, givet det workdate är vad du vill använda för kolumnrubriken, kommer detta sannolikt att behöva genereras dynamiskt. (Du kan ta bort den andra kolumnen "veckodag"-kolumnen från den ursprungliga källfrågan och flytta den till den yttre frågan.

Om jag inte visste workdate värden för rubrikerna innan jag körde frågan, då skulle jag välja att skapa en TILLFÄLLIG TABELL och fylla i den med resultat från den ursprungliga frågan och sedan fråga den temporära tabellen för att få workdate rubriker och den "första kolumnen" för att generera raderna. Sedan körde jag den faktiska frågan mot den tillfälliga tabellen.

För att upprepa, jag tror att det är bättre att du transformerar/pivoterar resultaten från din ursprungliga fråga i PHP, istället för att försöka göra det i SQL.



  1. Att lägga till mysql_real_escape_string() gör att tomma värden lagras i databasen

  2. Identitetskolumns värde hoppar plötsligt till 1001 i sql-servern

  3. Tävlingsvillkor med mysql_last_id()

  4. IDENTITY() vs IDENTITY() i SQL Server:Vad är skillnaden?