Mysql
 sql >> база данни >  >> RDS >> Mysql

PHP и Mysql заявка, използвайте PHP за преобразуване на ред в колони

Възможно е да получите резултата с помощта на SQL заявка, но това не е тривиално.

Но преди да тръгнете по този път, препоръчвам ви да помислите за различен подход.

Тъй като заявката връща сравнително малък набор от редове, можете вместо това да извлечете целия набор от резултати в PHP като двуизмерен масив.

Помислете за доста прост случай като илюстрация:

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

Можем да направим fetchAll и да получим двуизмерен масив, след което да преминем през масива и да извлечем стойностите по колони, а не по редове. Една от възможностите е да трансформираме масива, който получаваме, в нов масив, който изглежда така:

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

Всъщност не е необходимо да правите трансформацията, можете да обходите оригиналния масив. Но отделянето на трансформацията като отделна стъпка вероятно ще направи кода ви малко по-лесен, когато стигнете до действителното генериране на изхода в страницата. (Изглежда като достатъчно често срещан проблем, че някой вероятно е написал функция, която извършва трансформацията на масива, която искате. Не мисля, че има вграден PHP, който да го прави.

заглавия:

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

редове:

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

За малък набор от редове като вашия, бих избрал да направя това в PHP, а не в SQL.

Но вие попитахте как да го направите в SQL. Както казах по-рано, не е тривиално.

SQL изисква командата SELECT да дефинира всяка колона, която да бъде върната; броят и типовете на колоните не могат да бъдат динамични, когато операторът се изпълнява.

Ако изградим друга заявка (освен оригиналната заявка), която дефинира колоните и връща редовете, които очакваме да бъдат върнати със запазени места за стойностите, ние сме на половината път. Всичко, което остава, е да се направи външно свързване към редовете, върнати от оригиналната заявка, и условно да се върнат стойностите на колоните в съответните редове.

Този подход работи, ако имате предварително дефиниран набор от редове и колони, които трябва да бъдат върнати, особено когато оригиналният източник на ред е рядък и трябва да генерираме „липсващите“ редове. (Например, получаване на брой поръчани продукти и има много липсващи редове, няма добър начин за генериране на липсващите редове.

Например:

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

Това ще върне:

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

И така, това ни дава всички дефинирани колони и всички редове, които искаме да върнем. Първата колона е попълнена. Тази заявка всъщност все още не се нуждае от GROUP BY, но ще ни трябва, след като намерим съответствие с редовете в „реалния“ изходен набор от резултати.

„Трикът“ сега е съпоставяне на редовете от нашия източник и връщане на стойността от колона въз основа на подходящите условия.

Това, което ще генерираме, по същество е набор от резултати, който изглежда така:

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

След това ще "свием" редовете, като премахнем колоната foo от набора с резултати и направим GROUP BY на bar . Ще използваме агрегатна функция (или MAX, или SUM), като се възползваме от обработката, която правят с NULL стойности, за да произведем резултат като този:

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

Използвайки този доста тромав 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

Обърнете внимание, че mysource в заявката по-горе може да се замени с вграден изглед, обвивайки скоби около подходяща заявка, която връща желаните от нас редове.

Вграденият изглед с псевдоним като r е нашият източник за връщане на редовете, които искаме да върнем.

Изразите в списъка SELECT извършват условни тестове, за да изберат правилните стойности за всяка колона във всеки ред.

Като се има предвид редовният модел на операторите CASE, е възможно да се използва малко SQL, за да се генерира заявката, но това трябва да се направи като отделна стъпка. Резултатът от този SQL може да се използва за подпомагане на формирането на действителната заявка, от която се нуждаем.

Във вашия случай, предвид тази workdate е това, което искате да използвате за заглавката на колоната, това вероятно ще трябва да се генерира динамично. (Можете да изпуснете колоната „ден от седмицата“ на втората колона от оригиналната заявка за източник и да я преместите във външната заявка.

Ако не знаех workdate стойности за заглавията, преди да изпълня заявката, тогава бих избрал да създам ВРЕМЕННА ТАБЛИЦА и да я попълня с резултати от оригиналната заявка, след което да направя заявка във временната таблица, за да получа workdate заглавки и "първата колона" за генериране на редовете. След това бих изпълнил действителната заявка срещу временната таблица.

Да повторя, мисля, че ще е по-добре да направите преобразуването/завъртането на резултатите от първоначалната ви заявка в PHP, вместо да се опитвате да го направите в SQL.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mysql как да обединя таблици

  2. Проблем с UTF-8 знаци; това, което виждам, не е това, което съм съхранил

  3. Изберете най-ранната дата и час от списъка с отделни потребителски сесии

  4. MySQL включва нула редове, когато се използва COUNT с GROUP BY

  5. Как да избера MySQL база данни за използване с PDO в PHP?