Zend_Db_Select
является инструментом, помогающим строить
SQL-операторы SELECT, не зависящие от типа СУБД. Очевидно, он не
может быть идеальным, но он проделал значительный путь к тому, чтобы
помочь сделать ваши запросы переносимыми между серверными СУБД.
Кроме того, он помогает сделать ваши запросы устойчивыми
против SQL-инъекций.
Наиболее легкий способ создания экземпляра Zend_Db_Select
-- использование метода Zend_Db_Adapter::select()
.
<?php require_once 'Zend/Db.php'; $params = array ( 'host' => '127.0.0.1', 'username' => 'malory', 'password' => '******', 'dbname' => 'camelot' ); $db = Zend_Db::factory('PDO_MYSQL', $params); $select = $db->select(); // $select теперь является объектом, сконфигурированным для использования // исключительно с адаптером PDO_MYSQL ?>
Далее вы строите запрос SELECT, используя этот объект и его методы,
затем генерируете строку, которая передается Zend_Db_Adapter
для запросов (метод query()
) или извлечения
(группа методов fetch*()
).
<?php // // SELECT * // FROM round_table // WHERE noble_title = "Sir" // ORDER BY first_name // LIMIT 10 OFFSET 20 // // вы можете делать это последовательно... $select->from('round_table', '*'); $select->where('noble_title = ?', 'Sir'); $select->order('first_name'); $select->limit(10,20); // ...или в "потоковом" стиле (fluent style): $select->from('round_table', '*') ->where('noble_title = ?', 'Sir') ->order('first_name') ->limit(10,20); // извлечение результата $sql = $select->__toString(); $result = $db->fetchAll($sql); // также вы можете передавать сам объект $select // Zend_Db_Adapter достаточно "разумен", чтобы вызывать метод __toString() // для объектов Zend_Db_Select, чтобы получить из них строку запроса $result = $db->fetchAll($select); ?>
Еще вы можете применять связанные параметры в своих запросах вместо подстановки по порядку следования.
<?php // // SELECT * // FROM round_table // WHERE noble_title = "Sir" // ORDER BY first_name // LIMIT 10 OFFSET 20 // $select->from('round_table', '*') ->where('noble_title = :title') ->order('first_name') ->limit(10,20); // извлечение результатов с использованием связанных параметров $params = array('title' => 'Sir'); $result = $db->fetchAll($select, $params); ?>
Для извлечения столбцов из определенной таблицы используйте метод
from()
, задавая таблицу и столбцы, которые хотите получить
из таблицы. Вы можете использовать псевдонимы таблиц и столбцов,
также можете вызывать from()
столько раз, сколько вам нужно.
<?php // создание объекта $db, затем получение инструмента SELECT $select = $db->select(); // SELECT a, b, c FROM some_table $select->from('some_table', 'a, b, c'); // эквивалент: $select->from('some_table', array('a', 'b', 'c'); // SELECT bar.col FROM foo AS bar $select->from('foo AS bar', 'bar.col'); // SELECT foo.col AS col1, bar.col AS col2 FROM foo, bar $select->from('foo', 'foo.col AS col1'); $select->from('bar', 'bar.col AS col2'); ?>
Для извлечения столбцов с использованием объединения таблиц используйте
метод join()
. Сначала указывается имя присоединяемой
таблицы, затем условие соединения, и в заключение столбцы, которые
вы хотите получить из объединенных таблиц. Вы можете вызывать
join()
столько раз, сколько вам нужно.
<?php // создание объекта $db, затем получение инструмента SELECT $select = $db->select(); // // SELECT foo.*, bar.* // FROM foo // JOIN bar ON foo.id = bar.id // $select->from('foo', '*'); $select->join('bar', 'foo.id = bar.id', '*'); ?>
В настоящее время поддерживается только конструкция JOIN. Конструкции LEFT JOIN, RIGHT JOIN и т.д. не поддерживаются. Будущие релизы будут поддерживать их в форме, независимой от типа выбранной СУБД.
Для добавления условий WHERE, используйте метод where()
.
Вы можете передать либо обычную строку, либо строку с метками заполнения
и значения для подстановки с добавлением кавычек (подстановка
выполняется с помощью Zend_Db_Adapter::quoteInto
).
Повторные вызовы where()
будет добавлять условия через AND.
Если вам нужен OR, используйте метод orWhere()
.
<?php // создание объекта $db, затем получение SELECT $select = $db->select(); // // SELECT * // FROM round_table // WHERE noble_title = "Sir" // AND favorite_color = "yellow" // $select->from('round_table', '*'); $select->where('noble_title = "Sir"'); // встроенное значение $select->where('favorite_color = ?', 'yellow'); // подставляемое значение // // SELECT * // FROM foo // WHERE bar = "baz" // OR id IN("1", "2", "3") // $select->from('foo', '*'); $select->where('bar = ?', 'baz'); $select->orWhere('id IN(?)', array(1, 2, 3); ?>
Для группировки строк используйте метод group()
столько
раз, сколько вам нужно.
<?php // создание объекта $db, затем получение инструмента SELECT $select = $db->select(); // // SELECT COUNT(id) // FROM foo // GROUP BY bar, baz // $select->from('foo', 'COUNT(id)'); $select->group('bar'); $select->group('baz'); // эквивалентный вызов group(): $select->group('bar, baz'); // другой эквивалентный вызов group(): $select->group(array('bar', 'baz')); ?>
Для добавления условий HAVING используйте метод having()
.
Этот метод по функциям идентичен методу where()
.
Если вы вызываете having()
несколько раз, условия будут
добавляться через AND. Если вам нужен OR,
используйте метод orHaving()
.
<?php // создание объекта $db, затем получение инструмента SELECT $select = $db->select(); // // SELECT COUNT(id) AS count_id // FROM foo // GROUP BY bar, baz // HAVING count_id > "1" // $select->from('foo', 'COUNT(id) AS count_id'); $select->group('bar, baz'); $select->having('count_id > ?', 1); ?>
Для сортировки столбцов используйте метод order()
столько раз,
сколько нужно.
<?php // создание объекта $db, затем получение инструмента SELECT $select = $db->select(); // // SELECT * FROM round_table // ORDER BY noble_title DESC, first_name ASC // $select->from('round_table', '*'); $select->order('noble_title DESC'); $select->order('first_name'); // эквивалентный вызов order(): $select->order('noble_title DESC, first_name'); // другой эквивалентный вызов order(): $select->order(array('noble_title DESC', 'first_name')); ?>
Zend_Db_Select
предлагает независимую от типа СУБД поддержку
LIMIT. Для многих баз данных -- таких, как MySQL и PostgreSQL --
это относительно легко, так как они поддерживают синтаксис
"LIMIT :количество_строк [OFFSET :смещение]".
Для других баз данных -- таких, как Microsoft SQL и Oracle -- это
не так легко, поскольку они совсем не поддерживают конструкцию LIMIT.
MS-SQL имеет только конструкцию TOP, Oracle требует, чтобы
запрос был написан специальным образом для эмуляции LIMIT. Благодаря
внутреннему алгоритму работы Zend_Db_Select
,
мы можем "на лету" переписывать SELECT для эмуляции функционала
LIMIT из вышеупомянутых СУБД с открытыми исходниками.
Для ограничения возвращаемых результатов по количеству строк и смещению
используйте метод limit()
c количеством строк и смещением
(необязательный параметр).
<?php // простой "LIMIT :количество_строк" $select = $db->select(); $select->from('foo', '*'); $select->order('id'); $select->limit(10); // // в MySQL/PostgreSQL/SQLite это будет преобразовано в: // // SELECT * FROM foo // ORDER BY id ASC // LIMIT 10 // // а в Microsoft SQL это будет преобразовано в: // // SELECT TOP 10 * FROM FOO // ORDER BY id ASC // // // а теперь более сложный "LIMIT :количество_строк OFFSET :смещение" $select = $db->select(); $select->from('foo', '*'); $select->order('id'); $select->limit(10, 20); // // в MySQL/PostgreSQL/SQLite это будет преобразовано в: // // SELECT * FROM foo // ORDER BY id ASC // LIMIT 10 OFFSET 20 // // в Microsoft SQL, который не поддерживает смещения, это будет // преобразовано в нечто подобное: // // SELECT * FROM ( // SELECT TOP 10 * FROM ( // SELECT TOP 30 * FROM foo ORDER BY id DESC // ) ORDER BY id ASC // ) // // Zend_Db_Adapter автоматически сделает перобразования за вас // ?>
Zend_Db_Select
также предлагает ограничение, основанное
на страницах. Если вы хотите получить определенную "страницу"
результатов, используйте метод limitPage()
; сначала
передается номер требуемой страницы, затем количество строк,
которое показывается на каждой странице.
<?php // построение основы запроса SELECT... $select = $db->select(); $select->from('foo', '*'); $select->order('id'); // ... и ограничение до страницы 3, где каждая страница имеет 10 строк $select->limitPage(3, 10); // // в MySQL/PostgreSQL/SQLite это будет преобразовано в: // // SELECT * FROM foo // ORDER BY id ASC // LIMIT 10 OFFSET 20 // ?>