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

PHP og Mysql forespørgsel, brug PHP til at konvertere række til kolonner

Det er muligt at få resultatet ved hjælp af en SQL-forespørgsel, men det er ikke trivielt.

Men før du går den vej, anbefaler jeg, at du overvejer en anden tilgang.

Da forespørgslen returnerer et relativt lille sæt rækker, kan du i stedet hente hele resultatsættet i PHP som et todimensionelt array.

Overvej en ret simpel sag, som en illustration:

VÆLG foo, fee, fi, fo, fum FRA mytable BESTIL AF foofoo gebyr fi fo fum--- --- --- --- ---ABC 2 3 5 7DEF 11 13 17 19

Vi kunne lave en fetchAll og få et todimensionelt array, derefter sløjfe gennem arrayet og hente værdierne kolonnevis i stedet for rækkevis. En mulighed er at transformere det array, vi modtager, til et nyt array, der ser sådan ud:

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

Det er egentlig ikke nødvendigt at lave transformationen, du kunne gå den originale array. Men at adskille transformationen som et separat trin ville sandsynligvis gøre din kode lidt nemmere, når du rent faktisk kommer til at generere output på siden. (Det virker som et almindeligt nok problem, at nogen sandsynligvis har skrevet en funktion, der udfører den array-transformation, du ønsker. Jeg tror ikke, der er en PHP indbygget, der gør det.

overskrifter:

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

rækker:

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' }} 

For et lille sæt rækker, som du har, ville jeg vælge at gøre dette i PHP i stedet for i SQL.

Men du spurgte, hvordan man gør det i SQL. Som jeg sagde tidligere, er det ikke trivielt.

SQL kræver, at SELECT-sætningen definerer hver kolonne, der skal returneres; antallet og typen af ​​kolonnerne kan ikke være dynamiske, når sætningen udføres.

Hvis vi bygger en anden forespørgsel (bortset fra den oprindelige forespørgsel), der definerer kolonnerne og returnerer de rækker, vi forventer returneret med pladsholdere for værdierne, er vi halvvejs der. Det eneste, der er tilbage, er at lave en ydre joinforbindelse til de rækker, der returneres af den oprindelige forespørgsel, og betinget returnere kolonneværdierne på de relevante rækker.

Denne tilgang virker, hvis du har et foruddefineret sæt rækker og kolonner, som vi skal have returneret, især når den oprindelige rækkekilde er sparsom, og vi skal generere de "manglende" rækker. (For eksempel ved at få optællinger af bestilte produkter, og der er mange manglende rækker, er der ikke en god måde at generere de manglende rækker på.

For eksempel:

VÆLG r.bar , '' AS `ABC` , '' AS `DEF` FROM ( SELECT 'fee' AS bar UNION ALLE VÆLG 'fi' UNION ALLE VÆLG 'fo' UNION ALLE VÆLG 'fum' ) r GRUPPER EFTER r.bar 

Det vil returnere:

 bar ABC DEF --- --- --- gebyr fi fo fum 

Så det får os alle kolonnerne defineret, og alle de rækker, vi ønsker at returnere. Den første kolonne er udfyldt. Den forespørgsel har ikke rigtig brug for GROUP BY endnu, men vi får brug for den, når vi matcher rækkerne i det "rigtige" kilderesultatsæt.

"Tricket" nu er at matche rækkerne fra vores kilde og returnere værdien fra en kolonne baseret på de relevante betingelser.

Det, vi skal generere, er i bund og grund et resultatsæt, der ser sådan ud:

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

Så skal vi "kollapse" rækkerne ved at fjerne foo-kolonnen fra resultatsættet og lave en GROUP BY på bar . Vi kommer til at bruge en aggregeret funktion (enten MAX eller SUM), der udnytter den håndtering, de gør med NULL-værdier, for at producere et resultat som dette:

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

Bruger denne ret uhåndterlige 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 NÅR 'fum' THEN t.fum END END) SOM 'DEF' FRA ( SELECT 'foo' AS col UNION ALLE VÆLG 'fee' UNION ALLE VÆLG 'fi' UNION ALLE VÆLG 'fo' UNION ALLE VÆLG 'fum' ) r CROSS JOIN mysource t GRUPPE VED r.bar 

Bemærk, at mysource i forespørgslen ovenfor kan erstattes med en indlejret visning, hvor parens ombrydes omkring en passende forespørgsel, der returnerer de rækker, vi ønsker.

Den indbyggede visning kaldet r er vores kilde til at returnere de rækker, vi ønsker at returnere.

Udtrykkene i SELECT-listen udfører de betingede tests for at udvælge de rigtige værdier for hver kolonne i hver række.

I betragtning af det almindelige mønster af CASE-sætningerne er det muligt at bruge noget SQL til at hjælpe med at generere forespørgslen, men det skal gøres som et separat trin. Outputtet fra den SQL kan bruges til at danne den faktiske forespørgsel, vi har brug for.

I dit tilfælde givet den arbejdsdato er det, du vil bruge til kolonneoverskriften, skal denne sandsynligvis genereres dynamisk. (Du kan slippe den anden kolonne "ugedag" fra den oprindelige kildeforespørgsel og flytte den til den ydre forespørgsel.

Hvis jeg ikke kendte arbejdsdatoen værdier for overskrifterne, før jeg kørte forespørgslen, så ville jeg vælge at oprette en MIDLERTIDIG TABEL og udfylde den med resultater fra den oprindelige forespørgsel og derefter forespørge i den midlertidige tabel for at få arbejdsdatoen overskrifter og den "første kolonne" for at generere rækkerne. Så ville jeg køre selve forespørgslen mod den midlertidige tabel.

For at gentage, jeg tror, ​​du ville være bedre stillet at udføre transformationen/pivoten af ​​resultaterne fra din oprindelige forespørgsel i PHP, i stedet for at prøve at gøre det i SQL.



  1. Installation af RAC til en database med datafiler

  2. Minimalt eksempel på brug af vælg... til opdatering for at isolere rækker

  3. Syntaks for row_to_json med sqlalchemy

  4. PHP/MySQL Kritisk sektion