5.3. Zend_Db_Select
Пред. | Глава 5. Zend_Db | След.

## 5.3. Zend_Db_Select

### 5.3.1. Введение

`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);

    ?>

### 5.3.2. Извлечение столбцов

Для извлечения столбцов из определенной таблицы используйте метод `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');

    ?>

### 5.3.3. Объединение таблиц

Для извлечения столбцов с использованием объединения таблиц используйте метод `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 и т.д. не поддерживаются. Будущие релизы будут поддерживать их в форме, независимой от типа выбранной СУБД.

### 5.3.4. Условия WHERE

Для добавления условий 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);

    ?>

### 5.3.5. Группировка

Для группировки строк используйте метод `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'));

    ?>

### 5.3.6. Условия HAVING

Для добавления условий 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);

    ?>

### 5.3.7. Сортировка

Для сортировки столбцов используйте метод `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'));

    ?>

### 5.3.8. Ограничение по количеству строк и смещению

`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 автоматически сделает перобразования за вас
    //

    ?>

### 5.3.9. Ограничение по странице и количеству строк

`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
    //

    ?>

Пред. | Уровень выше | След.
5.2. Zend_Db_Profiler | Начало | 5.4. Zend_Db_Table