sql >> Databáze >  >> RDS >> Mysql

PHP a Mysql dotaz, použijte PHP pro převod řádku na sloupce

Je možné získat výsledek pomocí SQL dotazu, ale není to triviální.

Ale než se vydáte touto cestou, doporučuji vám zvážit jiný přístup.

Protože dotaz vrací relativně malou sadu řádků, můžete místo toho načíst celou sadu výsledků do PHP jako dvourozměrné pole.

Vezměme si jako ilustraci poměrně jednoduchý případ:

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

Mohli bychom provést fetchAll a získat dvourozměrné pole, pak procházet polem a načíst hodnoty po sloupcích, nikoli po řádcích. Jednou z možností je transformovat pole, které obdržíme, na nové pole, které vypadá takto:

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

Není opravdu nutné provádět transformaci, můžete projít původní pole. Ale oddělení transformace jako samostatný krok by pravděpodobně trochu usnadnilo váš kód, když se dostanete ke skutečnému generování výstupu na stránku. (Vypadá to jako dost častý problém, že někdo pravděpodobně napsal funkci, která provádí požadovanou transformaci pole. Nemyslím si, že existuje vestavěný modul PHP, který by to dělal.

nadpisy:

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

řádky:

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

Pro malou sadu řádků, jako máte vy, bych se rozhodl to udělat v PHP spíše než v SQL.

Ale ptal jste se, jak to udělat v SQL. Jak jsem řekl dříve, není to triviální.

SQL vyžaduje, aby příkaz SELECT definoval každý sloupec, který má být vrácen; počet a typy sloupců nemohou být při provádění příkazu dynamické.

Pokud vytvoříme další dotaz (kromě původního dotazu), který definuje sloupce a vrátí řádky, které očekáváme, se zástupnými symboly pro hodnoty, jsme na půli cesty. Zbývá pouze provést vnější spojení s řádky vrácenými původním dotazem a podmíněně vrátit hodnoty sloupců na příslušných řádcích.

Tento přístup funguje, pokud máte předdefinovanou sadu řádků a sloupců, které potřebujeme vrátit, zvláště když je původní zdroj řádků řídký a potřebujeme vygenerovat „chybějící“ řádky. (Například, když získáte počty objednaných produktů a mnoho chybějících řádků, neexistuje dobrý způsob, jak chybějící řádky vygenerovat.

Například:

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

To se vrátí:

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

Takže dostaneme všechny definované sloupce a všechny řádky, které chceme vrátit. První sloupec je vyplněn. Tento dotaz zatím ve skutečnosti nepotřebuje GROUP BY, ale budeme ho potřebovat, jakmile se přiřadíme k řádkům ze "skutečné" zdrojové sady výsledků.

„Trik“ nyní spočívá v porovnávání řádků z našeho zdroje a vrácení hodnoty ze sloupce na základě vhodných podmínek.

To, co vygenerujeme, je v podstatě sada výsledků, která vypadá takto:

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

Poté řádky "sbalíme" odstraněním sloupce foo z výsledkové sady a provedením GROUP BY na bar . Použijeme agregační funkci (buď MAX nebo SUM) s využitím manipulace, kterou provádějí s hodnotami NULL, k vytvoření výsledku, jako je tento:

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

Použití tohoto poněkud nepraktického 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

Všimněte si, že mysource ve výše uvedeném dotazu lze nahradit vloženým pohledem, který obklopí závorky kolem vhodného dotazu, který vrátí řádky, které chceme.

Vložený pohled s aliasem r je naším zdrojem pro vrácení řádků, které chceme vrátit.

Výrazy v seznamu SELECT provádějí podmíněné testy, aby vybraly správné hodnoty pro každý sloupec v každém řádku.

Vzhledem k pravidelnému vzoru příkazů CASE je možné použít nějaké SQL k vygenerování dotazu, ale to musí být provedeno jako samostatný krok. Výstup z tohoto SQL lze použít k vytvoření skutečného dotazu, který potřebujeme.

Ve vašem případě s ohledem na workdate je to, co chcete použít pro záhlaví sloupce, bude pravděpodobně muset být generováno dynamicky. (Tento druhý sloupec „den v týdnu“ můžete vypustit z původního zdrojového dotazu a přesunout jej do vnějšího dotazu.

Kdybych neznal workdate hodnoty pro nadpisy před spuštěním dotazu, pak bych se rozhodl vytvořit TEMPORARY TABLE a naplnit ji výsledky z původního dotazu a poté dotazovat dočasnou tabulku, abych získal workdate záhlaví a "první sloupec" pro generování řádků. Pak bych spustil skutečný dotaz proti dočasné tabulce.

Abych to zopakoval, myslím, že by bylo lepší provést transformaci/pivot výsledků z vašeho původního dotazu v PHP, než se o to pokoušet v SQL.



  1. Exportujete Google App Engine Datastore do MySQL?

  2. Nastavte časový limit připojení k databázi Oracle 10g v Javě

  3. Scénáře a kroky získají problém poslední změny

  4. Nastavte řazení databází v Entity Framework Code-First Initializer