# Zend_Db_Select

## Обзор

Объект Zend_Db_Select представляет SQL-оператор `SELECT`. Класс имеет методы для добавления отдельных частей запроса. Вы можете определять некоторые части запроса, используя методы PHP и структуры данных, и класс формирует корректный синтаксис SQL. После того, как построен запрос, можно выполнять его так же, как если бы он был написан в виде строки.

В число достоинств Zend_Db_Select входит:

- Объектно-ориентированные методы для "покусочного" построения SQL-запросов;

- Не зависящая от типа БД абстракция некоторых частей SQL-запроса;

- Автоматическое в большинстве случаев заключение в кавычки идентификаторов метаданных для поддержки идентификаторов, содержащих зарезервированные SQL слова и спецсимволы;

- Заключение в кавычки идентификаторов и значений для снижения угрозы атак с использованием SQL-инъекций.

Использование Zend_Db_Select не обязательно. Для очень простых запросов SELECT обычно проще указать SQL-запрос целиком в виде строки и выполнить его, используя такие методы адаптера, как `query()` или `fetchAll()`. Использование Zend_Db_Select полезно, если нужно собрать запрос SELECT в процессе или основываясь на условной логике.

## Создание объекта Select

Вы можете создавать экземпляр объекта Zend_Db_Select, используя метод `select()` объекта Zend_Db_Adapter_Abstract.

### Пример использования метода select() адаптера БД

    $db = Zend_Db::factory( ...опции... );
    $select = $db->select();

Другой способ состоит в создании объекта Zend_Db_Select через конструктор, при этом в качестве аргумента указывается адаптер БД.

### Пример создания нового объекта Select

    $db = Zend_Db::factory( ...опции... );
    $select = new Zend_Db_Select($db);

## Построение запросов Select

При построении запроса вы можете добавлять по одному его предложения. Предложение - это часть SQL-оператора, не представляющая собой законченный оператор; например, предложение WHERE. Для каждого предложения есть свой метод Zend_Db_Select.

### Пример использования методов для добавления предложений

    // Создание объекта Zend_Db_Select
    $select = $db->select();

    // Добавление предложения FROM
    $select->from( ...определение таблицы и столбцов... )

    // Добавление предложения WHERE
    $select->where( ...определение критериев поиска... )

    // Добавление предложения ORDER BY
    $select->order( ...определение критериев сортировки... );

Вы также можете использовать большинство методов объекта Zend_Db_Select в так называемом fluent interface. Fluent interface означает, что каждый метод возвращает ссылку на тот объект, в котором он был вызван, поэтому вы можете вызывать другой метод непосредственно за ним.

### Пример использования fluent interface

    $select = $db->select()
        ->from( ...определение таблицы и столбцов... )
        ->where( ...определение критериев поиска... )
        ->order( ...определение критериев сортировки... );

Этот пример демонстрирует применение fluent interface, но в любом случае вы можете использовать стандартный подход. Часто бывает необходимо использовать стандартный подход - например, когда нужно выполнить некоторую логику до добавления предложения в запрос.

### Добавление предложения FROM

Указывайте таблицу для запроса, используя метод `from()`. Вы можете задавать имя таблицы в виде простой строки, Zend_Db_Select добавит идентификатор, заключив в кавычки имя таблицы, поэтому вы можете использовать специальные символы.

#### Пример использования метода from()

    // Строит запрос:
    //   SELECT *
    //   FROM "products"

    $select = $db->select()
                 ->from( 'products' );

Вы можете также задавать корреляционное (называемое также "псевдонимом") имя таблицы. В этом случае вместо простой строки используйте ассоциативный массив корреляционных имен и действительных имен таблиц. В других предложениях SQL-запроса используйте это корреляционное имя. Если в вашем запросе объединяется более одной таблицы, то Zend_Db_Select генерирует уникальные корреляционные имена, основанные на именах таблиц, для всех таблиц, для которых не были заданы корреляционные имена.

#### Пример задания корреляционного имени таблицы

    // Строит запрос:
    //   SELECT p.*
    //   FROM "products" AS p

    $select = $db->select()
                 ->from( array('p' => 'products') );

Некоторые СУРБД поддерживают спецификатор схемы для таблицы. Вы можете задавать имя таблицы в виде "`имяСхемы.имяТаблицы`". Zend_Db_Select заключит в кавычки все части по отдельности.

#### Пример задания имени схемы

    // Строит запрос:
    //   SELECT *
    //   FROM "myschema"."products"

    $select = $db->select()
                 ->from( 'myschema.products' );

    // или

    $select = $db->select()
                 ->from('products', '*', 'myschema');

### Добавление колонок

Во втором аргументе метода `from()` вы можете задавать столбцы для выборки из соответствующей таблицы. Если вы не укажете столбцы для выборки, то по умолчанию будет подставлен метасимвол "`*`", означающий "все столбцы".

Вы можете перечислить столбцы в простом массиве строк или в ассоциативном массиве псевдонимов столбцов и их имен. Если в запросе нужен только один столбец, и к нему не нужен псевдоним, то можно передать строку с его именем вместо массива.

Если вы передали пустой массив в качестве аргумента для столбцов, то ни один столбец из соответствующей таблицы не будет включен в результат выборки. См. пример кода в разделе про метод `join()`.

Вы можете указать имя столбца как "`корреляционноеИмя.имяСтолбца`". Zend_Db_Select заключит в кавычки все части по отдельности. Если вы не укажете корреляционное имя для столбца, то используется корреляционное имя таблицы, указанной в текущем вызове метода `from()`.

#### Пример указания столбцов

    // Строит запрос:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'product_name'));

    // Строит тот же запрос с указанием корреляционных имен:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('p.product_id', 'p.product_name'));

    // Строит тот же запрос с псевдонимом для одного столбца:
    //   SELECT p."product_id" AS prodno, p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('prodno' => 'product_id', 'product_name'));

### Добавление столбцов выражений

Столбцы в SQL-запросах иногда представляют собой выражения, а не просто столбцы из таблицы. Выражения не должны иметь корреляционные имена и заключаться в кавычки. Если строка, обозначающая столбец запроса, содержит скобки, то Zend_Db_Select распознает ее как выражение.

Вы можете также явно создавать объект типа Zend_Db_Expr для того, чтобы предотвратить ошибочное распознавание строки как имени столбца. Zend_Db_Expr - мини-класс, содержащий только строку. Zend_Db_Select распознает объекты типа Zend_Db_Expr и преобразует их обратно в строку, но без таких действий, как заключение в кавычки и добавление корелляционных имен.

Использование Zend_Db_Expr не обязательно, если ваше выражение содержит скобки. Zend_Db_Select распознает выражение по скобкам и оперирует строкой как выражением, пропуская такие действия, как заключение в кавычки и добавление корреляционных имен.

#### Пример указания столбцов, содержащих выражения

    // Строит запрос:
    //   SELECT p."product_id", LOWER(product_name)
    //   FROM "products" AS p
    // Выражение со скобками неявно преобразуется в Zend_Db_Expr.

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'LOWER(product_name)'));

    // Строит запрос:
    //   SELECT p."product_id", (p.cost * 1.08) AS cost_plus_tax
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id',
                              'cost_plus_tax' => '(p.cost * 1.08)')
                       );

    // Построение того же запроса с явным использованием Zend_Db_Expr:
    //   SELECT p."product_id", p.cost * 1.08 AS cost_plus_tax
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id',
                              'cost_plus_tax' =>
                                  new Zend_Db_Expr('p.cost * 1.08'))
                        );

В примерах выше Zend_Db_Select не модифицирует строку для добавления корреляционных имен или заключения идентификаторов в кавычки. Если эти изменения необходимы для исключения неоднозначности, то вы должны произвести их в строке вручную.

Если имена столбцов являются ключевыми словами SQL или содержат специальные символы, то следует использовать метод адаптера `quoteIdentifier()` и включать результат в строку. Метод `quoteIdentifier()` использует заключение в кавычки для ограничения идентификатора, тем самым обозначается, что это идентификатор таблицы или столбца, а не другая часть синтаксиса SQL.

Ваш код будет более независимым от типа БД, если вы будете использовать метод `quoteIdentifier()` вместо непосредственного добавления кавычек в строке, поскольку некоторые БД используют нестандартные символы вместо кавычек. Метод `quoteIdentifier()` использует нужные символы, основываясь на типе адаптера. `quoteIdentifier()` также экранирует символы кавычек в самом идентификаторе.

#### Пример заключения в кавычки столбцов в выражении

    // Строится следующий запрос, при этом имя столбца "from" в выражении
    // заключается в кавычки:
    //   SELECT p."from" + 10 AS origin
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('origin' =>
                                  '(p.' . $db->quoteIdentifier('from') . ' + 10)')
                       );

### Добавление столбцов в существующую таблицу FROM или JOIN

Может потребоваться добавить столбцы в таблицу FROM или JOIN после того, как были вызваны соответствующие методы. Метод `columns()` позволяет добавлять определенные столбцы в любой момент до того, как будет выполнен запрос. Вы можете передавать столбцы в виде строки, объекта `Zend_Db_Expr` или массива этих элементов. Второй аргумент этого метода может быть опущен, это значит, что столбцы должны быть добавлены в таблицу FROM, иначе должно использоваться существующее корреляционное имя.

#### Пример добавления столбцов через метод `columns()`

    // Строится следующий запрос:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'), 'product_id')
                 ->columns('product_name');

    // Строится тот же запрос с указанием корреляционных имен:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->from(array('p' => 'products'), 'p.product_id')
                 ->columns('product_name', 'p');
                 // Можно также писать: columns('p.product_name')

### Добавление в запрос другой таблицы c помощью JOIN

Многие полезные запросы используют `JOIN` для объединения строк из разных таблиц. Вы можете добавлять таблицы в запрос, используя метод `join()` объекта Zend_Db_Select. Использование этого метода похоже на использование `from()` за тем исключением, что в большинстве случаев вам нужно будет также указать условие объединения.

#### Пример использования метода join()

    // Строит запрос:
    //   SELECT p."product_id", p."product_name", l.*
    //   FROM "products" AS p JOIN "line_items" AS l
    //     ON p.product_id = l.product_id

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'product_name'))
                 ->join(array('l' => 'line_items'),
                        'p.product_id = l.product_id');

Второй аргумент метода `join()` является строкой, содержащей условие объединения. Это выражение объявляет условие, при выполнении которого строки в одной таблице объединяются со сроками в другой таблице. Вы можете использовать корреляционные имена в этом выражении.

К выражению, указанному вами как условие объединения, не применяется автоматическое заключение в кавычки. Если нужно заключить в кавычки имена столбцов, то используйте `quoteIdentifier()` при формировании строки условия объединения.

Третий аргумент метода `join()` - массив имен столбцов, как и в методе `from()`. По умолчанию используется "`*`" вместо столбцов, поддерживаются корреляционные имена, выражения и Zend_Db_Expr - так же, как и в случае массива столбцов для метода `from()`.

Если из таблицы не нужно выбирать столбцы, то используйте пустой массив вместо перечисления столбцов. Это работает и для метода `from()`, но обычно требуется извлечь часть столбцов из основной таблицы в запросе, при этом может не требоваться получение столбцов из присоединяемой таблицы.

#### Пример извлечения без столбцов

    // Строит запрос:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p JOIN "line_items" AS l
    //     ON p.product_id = l.product_id

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'product_name'))
                 ->join(array('l' => 'line_items'),
                        'p.product_id = l.product_id',
                        array() ); // empty list of columns

Обратите внимание на пустой `array()` в примере выше вместо списка столбцов из присоединяемой таблицы.

SQL имеет несколько типов объединений. Ниже приведен список методов для поддержки различных типов объединений в Zend_Db_Select.

- `INNER JOIN`, методы `join(table, join, [columns])` и `joinInner(table, join, [columns])`.

  Возможно, наиболее часто используемый тип объединения. Строки из каждой таблицы сравниваются с использованием условия сравнения. Результат включает в себя только те строки, которые удовлетворяют условию объединения. Результат может быть пустым, если ни одна строка не удовлетворяет этому условию.

  Все СУРБД поддерживают этот тип объединения.

- `LEFT JOIN`, метод `joinLeft(table, condition, [columns])`.

  В результат входят все строки из таблицы слева и все соответствующие строки из таблицы справа. Если нет соответствующих строк из таблицы справа, то соответствующие столбцы в результате заполняются NULL.

  Все СУРБД поддерживают этот тип объединения.

- `RIGHT JOIN`, метод `joinRight(table, condition, [columns])`.

  Правое внешнее объединение дополняет левое внешнее объединение. В результат входят все строки из таблицы справа и все соответствующие строки из таблицы слева. Если нет соответствующих строк из таблицы слева, то соответствующие столбцы в результате заполняются NULL.

  Некоторые СУРБД не поддерживают этот тип объединения, но, как правило, любое правое объединение может быть заменено на левое посредством изменения порядка таблиц на обратный.

- `FULL JOIN`, метод `joinFull(table, condition, [columns])`.

  Полное внешнее объединение является как бы комбинацией левого и правого объединений. Все строки из обоих таблиц входят в результат, при этом объединяются друг с другом в одну строку результата, если соответствуют условию объединения, иначе объединяются с NULL вместо значений столбцов из другой таблицы.

  Некоторые СУРБД не поддерживают этот тип объединения.

- `CROSS JOIN`, метод `joinCross(table, [columns])`.

  Перекрестное объединение является декартовым произведением. Каждая строка в первой таблице объединяется с со всеми строками во второй таблице. Таким образом, количество строк в результате будет равно произведению числа строк в обоих таблицах. Вы можете фильтровать результат, используя условие в предложении WHERE, в этом случае перекрестное объединение подобно старому синтаксису объединений в SQL-89.

  Метод `joinCross()` не имеет параметров для определения условий объединения. Некоторые СУРБД не поддерживают этот тип объединения.

- `NATURAL JOIN`, метод `joinNatural(table, [columns])`.

  Естественное объединение сравнивает столбцы, имеющие одинаковые имена в обоих таблицах. Проверка производится на равенство; проверка на неравенство не является естественным объединением. Данным API поддерживаются только внутренние естественные объединения, даже если SQL поддерживает внешние естественные объединения.

  Метод `joinNatural()` не имеет параметров для определения условий объединения.

В дополнение к этим методам объединения вы можете упростить свои запросы, используя методы JoinUsing. Вместо предоставления полного условия объединения вы можете просто передавать имя столбца, по которому производится объединение, и Zend_Db_Select допишет условие объединения за вас.

#### Пример использования метода joinUsing()

    // Строится запрос:
    //   SELECT *
    //   FROM "table1"
    //   JOIN "table2"
    //   ON "table1".column1 = "table2".column1
    //   WHERE column2 = 'foo'

    $select = $db->select()
                 ->from('table1')
                 ->joinUsing('table2', 'column1')
                 ->where('column2 = ?', 'foo');

Каждый метод объединения из перечисленных выше имеет соответствующий ему метод JoinUsing.

- `joinUsing(table, join, [columns])` и `joinInnerUsing(table, join, [columns])`

- `joinLeftUsing(table, join, [columns])`

- `joinRightUsing(table, join, [columns])`

- `joinFullUsing(table, join, [columns])`

### Добавление предложения WHERE

Вы можете задавать условия для ограничения строк в результате выборки, используя метод `where()`. Первым аргументом этого метода является SQL-выражение, которое используется в предложении `WHERE` в данном запросе.

#### Пример использования метода where()

    // Строится запрос:
    //   SELECT product_id, product_name, price
    //   FROM "products"
    //   WHERE price > 100.00

    $select = $db->select()
                 ->from('products',
                        array('product_id', 'product_name', 'price'))
                 ->where('price > 100.00');

К выражениям для методов `where()` или `orWhere()` не применяется автоматическое заключение в кавычки. Если необходимо, чтобы имена столбцов были заключены в кавычки, то используйте метод `quoteIdentifier()` при формировании строки условия.

Второй аргумент метода `where()` является опциональным. Это значение подставляется в выражение. Zend_Db_Select заключает это значение в кавычки и подставляет вместо знака вопроса ("`?`") в выражении.

Этот метод принимает только один параметр. Если в выражение подставляется несколько значений, то нужно сформировать строку вручную, вставляя переменные и заключая их в кавычки самостоятельно.

#### Пример параметра в методе where()

    // Строит запрос:
    //   SELECT product_id, product_name, price
    //   FROM "products"
    //   WHERE (price > 100.00)

    $minimumPrice = 100;

    $select = $db->select()
                 ->from('products',
                        array('product_id', 'product_name', 'price'))
                 ->where('price > ?', $minimumPrice);

Вы можете вызывать метод `where()` несколько раз на одном и том же объекте Zend_Db_Select. Результирующий запрос объединяет в себе все термы с добавлением `AND` между ними.

#### Пример нескольких вызовов метода where()

    // Строит запрос:
    //   SELECT product_id, product_name, price
    //   FROM "products"
    //   WHERE (price > 100.00)
    //     AND (price < 500.00)

    $minimumPrice = 100;
    $maximumPrice = 500;

    $select = $db->select()
                 ->from('products',
                        array('product_id', 'product_name', 'price'))
                 ->where('price > ?', $minimumPrice)
                 ->where('price < ?', $maximumPrice);

Если вам нужно объединить термы с использованием `OR`, то используйте метод `orWhere()`. Этот метод используется так же, как и метод `where()`, за тем исключением, что определенный в этом вызове терм добавляется вместе с `OR` вместо `AND`.

#### Пример использования метода orWhere()

    // Строит запрос:
    //   SELECT product_id, product_name, price
    //   FROM "products"
    //   WHERE (price < 100.00)
    //     OR (price > 500.00)

    $minimumPrice = 100;
    $maximumPrice = 500;

    $select = $db->select()
                 ->from('products',
                        array('product_id', 'product_name', 'price'))
                 ->where('price < ?', $minimumPrice)
                 ->orWhere('price > ?', $maximumPrice);

Zend_Db_Select автоматически заключает в скобки все выражения, которые вы добавляете через методы `where()` или `orWhere()`. Это позволяет быть уверенным в том, что приоритет булевых операторов не приведет к другому результату вместо ожидаемого.

#### Пример заключения булевых выражений в скобки

    // Строит запрос:
    //   SELECT product_id, product_name, price
    //   FROM "products"
    //   WHERE (price < 100.00 OR price > 500.00)
    //     AND (product_name = 'Apple')

    $minimumPrice = 100;
    $maximumPrice = 500;
    $prod = 'Apple';

    $select = $db->select()
                 ->from('products',
                        array('product_id', 'product_name', 'price'))
                 ->where("price < $minimumPrice OR price > $maximumPrice")
                 ->where('product_name = ?', $prod);

В примере выше результаты могут отличаться от тех, что получаются без скобок, потому что `AND` имеет больший приоритет, чем `OR`. Zend_Db_Select добавляет скобки, Таким образом, результатом является то, что каждое выражение, добавленное в успешных вызовах `where()` более связанно, чем `AND`, объединяющее эти выражения.

### Добавление предложения GROUP BY

В языке SQL выражение `GROUP BY` позволяет ограничить количество строк в результатах запроса до одной стоки на каждое уникальное значение в столбцах, перечисленных в предложении `GROUP BY`.

В Zend_Db_Select вы можете задавать столбцы, используемые для определения групп строк, через метод `group()`. Аргументом этого метода является столбец или массив столбцов для подстановки в предложение `GROUP BY`.

#### Пример использования метода group()

    // Строит запрос:
    //   SELECT p."product_id", COUNT(*) AS line_items_per_product
    //   FROM "products" AS p JOIN "line_items" AS l
    //     ON p.product_id = l.product_id
    //   GROUP BY p.product_id

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id'))
                 ->join(array('l' => 'line_items'),
                        'p.product_id = l.product_id',
                        array('line_items_per_product' => 'COUNT(*)'))
                 ->group('p.product_id');

Как и для массива столбцов в методе `from()`, вы можете использовать корреляционные имена в именах столбцов, столбцы заключаются в кавычки в качестве идентификаторов, если строка не содержит скобок или является объектом типа Zend_Db_Expr.

### Добавление предложения HAVING

В SQL предложение `HAVING` применяет условие ограничения к группам строк. Это подобно тому, как предложение `WHERE` применяет условие ограничения к строкам. Но эти предложения не являются идентичными, поскольку условия `WHERE` применяются до группировки, в то время как условия `HAVING` применяется после группировки.

В Zend_Db_Select вы можете определять условия ограничения групп через метод `having()`. Его использование аналогично использованию метода `where()`. Первый аргумент является строкой, содержащей SQL-выражение. Опциональный второй аргумент - значение, которое используется для подстановки вместо метки заполнения в SQL-выражении. Выражения, переданные в нескольких вызовах метода `having()`, объединяются через булевый оператор `AND` или через булевый оператор `OR`, если вы используете метод `orHaving()`.

#### Пример использования метода having()

    // Строит запрос:
    //   SELECT p."product_id", COUNT(*) AS line_items_per_product
    //   FROM "products" AS p JOIN "line_items" AS l
    //     ON p.product_id = l.product_id
    //   GROUP BY p.product_id
    //   HAVING line_items_per_product > 10

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id'))
                 ->join(array('l' => 'line_items'),
                        'p.product_id = l.product_id',
                        array('line_items_per_product' => 'COUNT(*)'))
                 ->group('p.product_id')
                 ->having('line_items_per_product > 10');

К выражениям, переданным через методы `having()` или `orHaving()`, не применяется автоматическое заключение в кавычки. Если у вас есть имена столбцов, которые требуется заключить в кавычки, то используйте `quoteIdentifier()` при формировании строки условия.

### Добавление предложения ORDER BY

В SQL предложение `ORDER BY` задает один или более столбцов (или выражений), по которым сортируется результат запроса. Если перечислено несколько столбцов, то вторичные столбцы используются для принятия решения в ситуации "ничьи": если первичные столбцы содержат идентичные значения, то порядок сортировки определяется через вторичные столбцы. По умолчанию сортировка производится от меньших значений к большим. Вы можете также производить для данного столбца сортировку от больших значений к меньшим, указав ключевое слово `DESC` после этого столбца.

В Zend_Db_Select вы можете использовать метод `order()` для определения столбца или массива столбцов, по которым производится сортировка. Каждый элемент массива является строкой с именем столбца, опционально строка может содержать ключевое слово `ASC` или `DESC` после имени столбца и отделенное от него пробелом.

Как и в случае методов `from()` и `group()`, имена столбцов заключаются в кавычки в качестве идентификаторов, если они не содержат скобки и не являются объектами Zend_Db_Expr.

#### Пример использования метода order()

    // Строит запрос:
    //   SELECT p."product_id", COUNT(*) AS line_items_per_product
    //   FROM "products" AS p JOIN "line_items" AS l
    //     ON p.product_id = l.product_id
    //   GROUP BY p.product_id
    //   ORDER BY "line_items_per_product" DESC, "product_id"

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id'))
                 ->join(array('l' => 'line_items'),
                        'p.product_id = l.product_id',
                        array('line_items_per_product' => 'COUNT(*)'))
                 ->group('p.product_id')
                 ->order(array('line_items_per_product DESC',
                               'product_id'));

### Добавление предложения LIMIT

Некоторые СУРБД расширяют язык SQL предложением, известным как предложение `LIMIT`. Это предложение ограничивает количество строк в результате запроса до заданного вами количества. Вы можете также задать количество пропускаемых до начала вывода строк. Эта возможность облегчает выборку подмножества строк результата - например, для постраничного вывода результатов запроса.

В Zend_Db_Select вы можете использовать метод `limit()` для задания количества строк в выборке и количества пропускаемых строк. Первым аргументом этого метода является желаемое количество строк в результате запроса. Вторым аргументом - количество пропускаемых строк

#### Пример использования метода limit()

    // Строит запрос:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p
    //   LIMIT 10, 20

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'product_name'))
                 ->limit(10, 20);

Ситаксис `LIMIT` поддерживается не всеми СУРБД. Некоторые СУРБД используют другой синтаксис для поддержки аналогичной функциональности. Каждый класс Zend_Db_Adapter_Abstract включает в себя метод для генерации SQL, присущего данной СУРБД.

Используйте метод `limitPage()` в качестве альтернативного способа указания количества строк и смещения. Этот метод позволяет ограничить набор возвращаемых результатов подмножеством фиксированной длины, который является одним из последовательности подмножеств, составляющих весь набор результатов запроса. Другими словами, вы указываете длину "страницы" результатов в строках и порядковый номер страницы для извлечения. Номер страницы является первым аргументом в методе `limitPage()`, а длина страницы - вторым. Оба аргумента являются обязательными и не имеют значений по умолчанию.

#### Пример использования метода limitPage()

    // Строит запрос:
    //   SELECT p."product_id", p."product_name"
    //   FROM "products" AS p
    //   LIMIT 10, 20

    $select = $db->select()
                 ->from(array('p' => 'products'),
                        array('product_id', 'product_name'))
                 ->limitPage(2, 10);

### Добавление модификатора DISTINCT

Метод `distinct()` дает возможность добавлять ключевое слово `DISTINCT` в ваш запрос.

#### Пример использования метода distinct()

    // Строит запрос:
    //   SELECT DISTINCT p."product_name"
    //   FROM "products" AS p

    $select = $db->select()
                 ->distinct()
                 ->from(array('p' => 'products'), 'product_name');

### Добавление модификатора FOR UPDATE

Метод `forUpdate()` дает возможность добавлять модификатор `FOR UPDATE` в ваш запрос.

#### Пример использования метода forUpdate()

    // Строит запрос:
    //   SELECT FOR UPDATE p.*
    //   FROM "products" AS p

    $select = $db->select()
                 ->forUpdate()
                 ->from(array('p' => 'products'));

## Произведение запросов на выборку

Этот раздел объясняет, как производить запрос, представленный объектом Zend_Db_Select.

### Произведение запросов на выборку из адаптера БД

Вы можете производить запрос, представленный объектом Zend_Db_Select, посредством передачи его в качестве первого аргумента методу `query()` объекта Zend_Db_Adapter_Abstract. Используйте объекты Zend_Db_Select вместо строк запроса.

Метод `query()` возвращает объект Zend_Db_Statement или PDOStatement, в зависимости от типа адаптера.

#### Пример использования метода query() адаптера БД

    $select = $db->select()
                 ->from('products');

    $stmt = $db->query($select);
    $result = $stmt->fetchAll();

### Произведение запросов на выборку через объект Select

Вместо метода `query()` объекта адаптера можно использовать метод `query()` объекта Zend_Db_Select. Оба метода возвращают объект типа Zend_Db_Statement или PDOStatement, в зависимости от типа адаптера.

#### Пример использования метода query() объекта Select

    $select = $db->select()
                 ->from('products');

    $stmt = $select->query();
    $result = $stmt->fetchAll();

### Преобразование объекта Select в SQL-строку

Если нужно получить доступ к строковому представлению SQL-запроса, соответствующего данному объекту Zend_Db_Select, то используйте метод `__toString()`.

#### Пример использования метода __toString()

    $select = $db->select()
                 ->from('products');

    $sql = $select->__toString();
    echo "$sql\n";

    // Выводится будет строка:
    //   SELECT * FROM "products"

## Другие методы

Этот раздел описывает другие методы класса Zend_Db_Select, которые не были охвачены ранее: `getPart()` и `reset()`.

### Получение частей объекта Select

Метод `getPart()` возвращает представление определенной части вашего запроса. Например, вы можете использовать этот метод для получения строки выражения для предложения `WHERE`, массива столбцов, перечисленных для получения выборки по ним, значений количества и смещения для предложения `LIMIT`.

Возвращаемое значение не является строкой, содержащей фрагмент запроса SQL. Возвращаемое значение является внутренним представлением в объекте, обычно это массив, содержащий значения и выражения. Каждая часть запроса имеет различную структуру.

Единственным аргументом метода `getPart()` является строка, идентифицирующая часть запроса, которую требуется вернуть. Например, строка `'from'` соответствует той части запроса, которая хранит информацию о таблицах в предложении `FROM`, включая присоединяемые таблицы.

Zend_Db_Select определяет константы, которые вы можете использовать для частей SQL-запроса. Вы можете использовать эти константы или литеральные строки.

#### Константы, используемые методами getPart() и reset()

Константа | Строковое значение
--- | ---
`Zend_Db_Select::DISTINCT` | `'distinct'`
`Zend_Db_Select::FOR_UPDATE` | `'forupdate'`
`Zend_Db_Select::COLUMNS` | `'columns'`
`Zend_Db_Select::FROM` | `'from'`
`Zend_Db_Select::WHERE` | `'where'`
`Zend_Db_Select::GROUP` | `'group'`
`Zend_Db_Select::HAVING` | `'having'`
`Zend_Db_Select::ORDER` | `'order'`
`Zend_Db_Select::LIMIT_COUNT` | `'limitcount'`
`Zend_Db_Select::LIMIT_OFFSET` | `'limitoffset'`

#### Пример использования метода getPart()

    $select = $db->select()
                 ->from('products')
                 ->order('product_id');

    // Вы можете использовать строковой литерал для указания части запроса
    $orderData = $select->getPart( 'order' );

    // Можно использовать константу для указания той же части
    $orderData = $select->getPart( Zend_Db_Select::ORDER );

    // Возвращаемое значение может быть массивом, а не строкой
    // Каждая часть имет свою структуру
    print_r( $orderData );

### Сброс частей запроса в объекте Select

Через метод `reset()` вы можете очистить определенную часть SQL-запроса или все части запроса, если опустить аргумент.

Единственный аргумент метода является опциональным. Вы можете указать часть запроса для очистки, используя те же строки, которые используются для метода `getPart()`. Та часть запроса, которую вы указали, сбрасывается в состояние по умолчанию.

Если вы опустите этот параметр, то `reset()` сбрасывает все части запроса в состояние по умолчанию. Это делает объект Zend_Db_Select эквивалентным новому объекту - так же, как если бы вы его только что инстанцировали его.

#### Пример использования метода reset()

    // Строит запрос:
    //   SELECT p.*
    //   FROM "products" AS p
    //   ORDER BY "product_name"

    $select = $db->select()
                 ->from(array('p' => 'products')
                 ->order('product_name');

    // Changed requirement, instead order by a different columns:
    // Теперь нужна сортировка по другому столбцу:
    //   SELECT p.*
    //   FROM "products" AS p
    //   ORDER BY "product_id"

    // Очищаем соответствующую часть, теперь можно переопределить ее
    $select->reset( Zend_Db_Select::ORDER );

    // Задаем другой столбец
    $select->order('product_id');

    // Очищаем все части запроса
    $select->reset();