Относительно недавно при написании кода очередной модели, передо мной встала задача использования подзапроса (к примеру в join). При этом уже довольно давно я стараюсь как можно меньше писать запросов «в сыром» виде; использую для этого ООП обёртку Zend Framework. Однако, посмотрев в мануале, API, я, к своему удивлению, не нашёл необходимых средств. Но после обращения непосредственно к коду стало ясно, что вложенный запрос можно сделать очень просто!
Присутствие в коде внутреннего метода _join (файл Zend/Db/Select.php) следующей строки, дало понять, что не всё так безнадёжно:
Банально исходя из того, что для $name instanceof Zend_Db_Select заложена какая-то своя логика, пробуем следующее:
А в результате работы скрипта получаем:
Вуаля! Собрался абсолютно правильный запрос.
Это очень важная особенность, т.к. развязывает руки при написании более абстрактных моделей. К примеру, создаём несколько методов, которые не просто возвращают какие-то данные, а запросы в виде объектов Zend_Db_Select. Тогда эти запросы можно будет модифицировать, встраивать в другие, т.е. избегать написания одного и того же SQL кода в разных местах, а это уже большой плюс при поддержке и модификации кода.
P.S. Данная фича работает уже достаточно давно и почему её до сих пор не внесли в мануал, PHPDoc, по которым получено API, я, честно говоря, не понимаю совсем.
Присутствие в коде внутреннего метода _join (файл Zend/Db/Select.php) следующей строки, дало понять, что не всё так безнадёжно:
773. } else if ($name instanceof Zend_Db_Expr || $name instanceof Zend_Db_Select) {
* This source code was highlighted with Source Code Highlighter.
Банально исходя из того, что для $name instanceof Zend_Db_Select заложена какая-то своя логика, пробуем следующее:
$firstQuery = $db->select()
->from(array('u' => 'user'),
array())
->join(array('s2u' => 'site2user'),
's2u.userId = u.id',
array('siteId'))
->columns(array('userCount' => 'count(*)'))
->group('s2u.siteId');
$secondQuery = $db->select()
->from(array('s' => 'site'),
array('siteId' => 'id',
'site' => 'title'))
->join(array('n' => $firstQuery),
'n.siteId = s.id',
array('userCount'));
echo $secondQuery->assemble();
* This source code was highlighted with Source Code Highlighter.
А в результате работы скрипта получаем:
SELECT `s`.`id` AS `siteId`, `s`.`title` AS `site`, `n`.`userCount` FROM `site` AS `s`
INNER JOIN (SELECT `su`.`siteId`, count(*) AS `userCount` FROM `user` AS `u`
INNER JOIN `site2user` AS `su` ON s2u.userId = u.id GROUP BY `s2u`.`siteId`) AS `n` ON n.siteId = s.id
* This source code was highlighted with Source Code Highlighter.
Вуаля! Собрался абсолютно правильный запрос.
Это очень важная особенность, т.к. развязывает руки при написании более абстрактных моделей. К примеру, создаём несколько методов, которые не просто возвращают какие-то данные, а запросы в виде объектов Zend_Db_Select. Тогда эти запросы можно будет модифицировать, встраивать в другие, т.е. избегать написания одного и того же SQL кода в разных местах, а это уже большой плюс при поддержке и модификации кода.
P.S. Данная фича работает уже достаточно давно и почему её до сих пор не внесли в мануал, PHPDoc, по которым получено API, я, честно говоря, не понимаю совсем.