Възможно е да получите резултата с помощта на 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.