Знакомимся с Query Builder

Комментарии: 16  Просмотры: 21 653

В прошлых уроках мы использовали обычные SQL-запросы в связке с «подготовленными операторами». В Кохане также существует способ формирования запросов с помощью специальных методов, что иногда сильно упрощает составление сложных запросов с многими параметрами, а также улучшает читаемость кода. Такой своеобразный конструктор запроса так и называется — Query Builder.
Например, запрос из урока Создаем первую Модель, который выглядел так:

$query = DB::query(Database::SELECT, "SELECT * FROM ". $this->_tableArticles);

с использованием Query Builder-а будет выглядеть следующим образом:

$query = DB::select()
        ->from($this->_tableArticles);

Построение запроса начинается с метода DB::select(), который возвращает экземпляр класса Database_Query_Builder_Select и делает возможным сборку последующих методов для текущего объекта в одну цепочку.
По сути этот код:

$query = DB::select();

создает в себе следующую часть запроса:

SELECT *

Но это еще не все. Метод select() также может принимать список параметров — полей таблицы:

$query = DB::select('title', 'author', 'date');

Этот код сформирует уже часть запроса на выборку данных из определенных полей:

SELECT `title`, `author`, `date`

Обратите внимание, что поля обрамляются апострофами и это хорошо, так как иначе поле date вызвало бы ошибку. Как вы наверное догадались по первому примеру, чтобы указать, из какой таблицы выбирать данные, нужно использовать метод from(), передав в качестве параметра название этой таблицы.
Если у нас есть массив с названиями полей таблицы, совершенно не обязательно преобразовывать его в список параметров, разделенных запятой. В таких случаях используется метод select_array():

$columns = array('title', 'author', 'date');
$query = DB::select_array($columns)
        ->from('articles');

Выполнив этот код мы опять же получим запрос:

SELECT `title`, `author`, `date` FROM `articles`

Для того, чтобы манипулировать условиями запросов существуют методы where(), and_where() и or_where(). Все эти методы принимают три параметра: название поля таблицы или алиаса, арифметический оператор (равно, больше, меньше и т.д.) и значение, которое будет искаться. Небольшой пример:

$query = DB::select('title', 'author', 'date')
        ->from('articles')
        ->where('id', '=', 1)
        ->or_where('id', '=', 2)
        ->and_where('date', '<', 'time')

При выполнении этого кода сформируется такой запрос:

SELECT `title`, `author`, `date` 
FROM `articles` 
WHERE `id` = 1 
OR `id` = 2 
AND `date` < 1334092257

Нужно отметить, что метод where() используется достаточно аккуратно. Если вы случайно вместо and_where() напишете второй раз where() или такое произойдет в процессе исполнения программы, то вместо добавления еще одного условия WHERE в запрос, произойдет все-таки добавление AND и это позволяет нам не заморачиваться дополнительными проверками для таких ситуаций.
Что делать, если нам нужно получить множественное условие. Допустим выбрать статью с идентификатором 1 и датой публикации более суток назад или выбрать статью с идентификатором 2 и датой публикации менее суток назад. В таких случаях для методов where(), and_where() и or_where() используются специальные «скобки»:

$query = DB::select('id', 'alt_title', 'title', 'content_short',  'author', 'date')
        ->from('articles')
        ->where_open()
        ->where('id', '=', 1)
        ->and_where('date', '<', time() - 86400)
        ->where_close()
        ->or_where_open()
        ->where('id', '=', 2)
        ->and_where('date', '>', time() - 86400)
        ->or_where_close();

Как видите, написание чем-то похоже на связки операторов if(): и endif; или foreach(): и endforeach;, которые довольно часто используются в шаблонах (я постоянно их там использую). А запрос, который мы получим, выглядит так:

SELECT `id`, `alt_title`, `title`, `content_short`, `author`, `date` 
FROM `articles` 
WHERE (`id` = 1 AND `date` < 1334007425) 
OR (`id` = 2 AND `date` > 1334007425)

Но получить правильные данные — это не всегда полностью все, что требуется. Иногда нужно получить эти данные в правильном порядке. Для этого в Query Builder-е есть метод order_by(), который также очень просто использовать:

$query = DB::select()
        ->from('articles')
        ->order_by('id');

Как вы уже догадались, сформируется такой запрос:

SELECT * 
FROM `articles` 
ORDER BY `id`

Вторым параметром в методе можно указывать направление сортировки. Также можно вызывать сразу несколько методов order_by(). В таком случае сортировка будет вестись сначала по первому указанному столбцу, потом по второму и так далее:

$query = DB::select()
        ->from($this->_tableArticles)
        ->order_by('date', 'DESC')
        ->order_by('id', 'ASC');

Получится запрос:

SELECT * 
FROM `articles` 
ORDER BY `date` DESC, `id` ASC

Кроме уже рассмотренных методов существуют еще такие методы как limit() и offset(). Первый метод используется для получения определенного количества результатов (например, для вывода не всех новостей, а только десяти последних). Второй метод иногда используется в связке с первым для создания определенной точки отсчета, от которой будут отсчитываться нужные нам результаты (например, если мы находимся на третьей странице сайта, где на каждой странице выводится десять статей, нам нужно будет вывести десять статей начиная уже от двадцатой статьи, а не от первой).
Основные методы Query Builder-а, с помощью которых можно строить большую часть запросов, мы с вами рассмотрели. А об остальных методах поговорим в следующем уроке.

<< Назад | Вперед >> | Обсудить на форуме


К записи оставлено 16 коммент.

Очередное спасибо за очередной хороший урок!)
Честно говоря не вижу особого смысла в использовании данной фичи. Наглядности не прибавилось, скорее наоборот. Разве что для любителей приводить все к единообразному синтаксису…
Ждем ORM! )

Честно говоря я тоже так считаю. Используя все эти билдеры рискуешь забыть SQL и не факт, что когда-нибудь не понадобиться написать какой-то запрос в проекте, а ты забыл как пишется SELECT.

так и использование framework’s черевато забыванием писать mysql_query() и прочей шелухи

с таким суждением для Вас и ОРМ наглядности не прибавит.

Честно говоря для меня иногда проще написать запрос, чем задумываться, а как же этот запрос будет выглядеть при использовании qb или orm. Да и шустрее работать будет всяко.

тут уже вопрос в том для чего это делается. ОРМ и прочие технологии применяются в основном для переносимости, проект может работать как под MySQL так и под Oracle. и чтобы перенос был легким применяются технологии, абстракции и прочее. понятно что мелким проектам это не нужно, но если проект серьезный, то лучше реализовать это через ОРМ, даже если проще написать прямой запрос. так как потом бегать по всему коду проекта и править запросы не вариант. плюс если идет коммандная разработка и БД постоянно изменяется то орм предоставит больше удобства в работе чем прямые запросы. хотя бы освободит от перебиваний таблиц.

плюс с орм уходит рутина типа CRUD, связи, результаты, к примеру проект 356 таблиц, для всех писать это утомительно долго.

Ну тогда может получиться, что написал просто, а на деле все это будет безбожно тормозить. Серьезный сложный проект -это обычно тяжелый проект в плане запросов. А для таких проектов мне почему-то как раз рекомендуют не использовать ОРМ. Получается непонятная ситуация. Вроде для простых — не требуется, а для сложных — нежелательно.

А кто сказал, что сложные запросы в орм не реализуемые? Даже если не будет использоваться готовая орм, то при проектировании проекта, будет спроектирована своя орм ну или ее подобие, т.е. абстрактная модель с набором стандартных функций (CRUD к приеру), вывод результатов, построение запросов, связи и тд. Если честно не видел ни одного сложного проекта без ОРМ (в основном Doctrine иногда проскакивает php-activerecord, ну или как писал выше свой велосипед)

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

я когда начинал своё знакомство с кохана — черпал инфо отсюда
http://kerkness.ca/kowiki/doku.php?id=building_complex_select_statements
рускоязычного толкового мануала тогда не было…

кстати, хорошая идея написать статью про всякие фенечки из билдера
всё я к хостингу руки не приложу, поставил вордпресс да не особо понравился — криво там мультиязычность становится
планирую скромное подобие для своих нужд накатать на кохане, но всё пока в процессе начинаний — работы слишком много

А я класс открывал и там смотрел методы, какие есть )

Никак не могу составить выборку колонки ‘name’ из бд ‘citys’, где значение колонки ‘codes’ будет равняться $codes. Всё дело уперается в то, что вставляю переменную $codes — кохана фыркает. Если же вставляю число, то всё нормально. Помогите, пожалуйсто.

->where(‘codes’, ‘=’, $codes)

И правильно будет cities, а не citys. Если по английски :)

Спасибо автору за труд. На самом деле Query Builder очень полезный инструмент когда ты хочешь сделать поиск по нескольким таблицам с использованием join. Например у вас есть одна большая форма которая содержит поля аналогичные полям в разных таблицах и вам нужно оптимизировать поиск таким образом чтобы не джоинить таблицы поля которых вы не указали в форме — вот тут то QueryBuilder просто незаменим….



Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.