{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11}} == Введение == Конструктор запросов Laravel предоставляет удобный, выразительный интерфейс для создания и выполнения запросов к базе данных. Он может использоваться для выполнения большинства типов операций и работает со всеми поддерживаемыми СУБД. Конструктор запросов Laravel использует привязку параметров к запросам средствами PDO для защиты вашего приложения от SQL-инъекций. Нет необходимости экранировать строки перед их передачей в запрос. == Получение результатов == **Получение всех записей таблицы** Используйте метод %%table()%% фасада %%(t)DB%% для создания запроса. Метод %%table()%% возвращает экземпляр конструктора запросов для данной таблицы, позволяя вам "прицепить" к запросу дополнительные условия и в итоге получить результат методом %%get()%%: %% get(); return view('user.index', ['users' => $users]); } } %% Метод %%get()%% возвращает объект %%(t)Illuminate\Support\Collection%% (для версии 5.2 и ранее - массив) c результатами, в котором каждый результат - это экземпляр PHP-объекта %%(t)StdClass%%. Вы можете получить значение каждого столбца, обращаясь к столбцу как к свойству объекта: %% foreach ($users as $user) { echo $user->name; } %% **Получение одной строки/столбца из таблицы** Если вам необходимо получить только одну строку из таблицы БД, используйте метод %%first()%%. Этот метод вернёт один объект %%(t)StdClass%%: %% $user = DB::table('users')->where('name', 'John')->first(); echo $user->name; %% Если вам не нужна вся строка, вы можете извлечь одно значение из записи методом %%value()%%. Этот метод вернёт значение конкретного столбца: %% $email = DB::table('users')->where('name', 'John')->value('email'); %% **Получение списка всех значений одного столбца** %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Если вы хотите получить массив значений одного столбца, используйте метод %%pluck()%%. В этом примере мы получим коллекцию (для версии 5.2 и ранее - массив) названий ролей: ~%% $titles = DB::table('roles')->pluck('title'); foreach ($titles as $title) { echo $title; } ~%% Вы можете указать произвольный ключ для возвращаемой коллекции (для версии 5.2 и ранее - массива): ~%% $roles = DB::table('roles')->pluck('title', 'name'); foreach ($roles as $name => $title) { echo $title; } ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01, 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) Если вы хотите получить массив значений одного столбца, используйте метод %%lists()%%. В этом примере мы получим массив названий ролей: ~%% $titles = DB::table('roles')->lists('title'); foreach ($titles as $title) { echo $title; } ~%% Вы можете указать произвольный ключ для возвращаемого массива: ~%% $roles = DB::table('roles')->lists('title', 'name'); foreach ($roles as $name => $title) { echo $title; } ~%% %% === Получение результатов из таблицы "по кускам" === Если вам необходимо обработать тысячи записей БД, попробуйте использовать метод %%chunk()%%. Этот метод получает небольшой "кусок" результатов за раз и отправляет его в замыкание для обработки. Этот метод очень полезен для написания ((/docs/v5/artisan Artisan-команд)), которые обрабатывают тысячи записей. Например, давайте обработаем всю таблицу %%(t)users%% "кусками" по 100 записей: %% DB::table('users')->orderBy('id')->chunk(100, function ($users) { foreach ($users as $user) { // } }); %% Вы можете остановить обработку последующих "кусков" вернув %%(t)false%% из замыкания: %% DB::table('users')->orderBy('id')->chunk(100, function ($users) { // Обработка записей... return false; }); %% === Агрегатные функции === Конструктор запросов содержит множество агрегатных методов, таких как **count**, **max**, **min**, **avg** и **sum**. Вы можете вызывать их после создания своего запроса: %% $users = DB::table('users')->count(); $price = DB::table('orders')->max('price'); %% Разумеется, вы можете комбинировать эти методы с другими условиями: %% $price = DB::table('orders') ->where('finalized', 1) ->avg('price'); %% == Выборка (%%(t)SELECT%%) == **Указание столбцов для выборки** Само собой, не всегда вам необходимо выбрать все столбцы из таблицы БД. Используя метод %%select()%% вы можете указать необходимые столбцы для запроса: %% $users = DB::table('users')->select('name', 'email as user_email')->get(); %% Метод %%distinct()%% позволяет вернуть только отличающиеся результаты: %% $users = DB::table('users')->distinct()->get(); %% Если у вас уже есть экземпляр конструктора запросов и вы хотите добавить столбец к существующему набору для выборки, используйте метод %%addSelect()%%: %% $query = DB::table('users')->select('name'); $users = $query->addSelect('age')->get(); %% == Сырые выражения == Иногда вам может понадобиться использовать уже готовое SQL-выражение в вашем запросе. Такие выражения вставляются в запрос напрямую в виде строк, поэтому будьте внимательны и не допускайте возможностей для SQL-инъекций! Для создания сырого выражения используйте метод %%DB::raw()%%: %% $users = DB::table('users') ->select(DB::raw('count(*) as user_count, status')) ->where('status', '<>', 1) ->groupBy('status') ->get(); %% == Объединения (%%(t)JOIN%%) == **Объединение %%(t)INNER JOIN%%** Конструктор запросов может быть использован для объединения данных из нескольких таблиц через %%JOIN%%. Для выполнения обычного объединения "inner join", используйте метод %%join()%% на экземпляре конструктора запросов. Первый аргумент метода %%join()%% - имя таблицы, к которой необходимо присоединить другие, а остальные аргументы указывают условия для присоединения столбцов. Как видите, вы можете объединять несколько таблиц одним запросом: %% $users = DB::table('users') ->join('contacts', 'users.id', '=', 'contacts.user_id') ->join('orders', 'users.id', '=', 'orders.user_id') ->select('users.*', 'contacts.phone', 'orders.price') ->get(); %% **Объединение %%(t)LEFT JOIN%%** Для выполнения объединения "left join" вместо "inner join", используйте метод %%leftJoin()%%. Этот метод имеет ту же сигнатуру, что и метод %%join()%%: %% $users = DB::table('users') ->leftJoin('posts', 'users.id', '=', 'posts.user_id') ->get(); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) **Объединение %%(t)CROSS JOIN%%** Для выполнения объединения CROSS JOIN используйте метод %%crossJoin()%% с именем таблицы, с которой нужно произвести объединение. CROSS JOIN формирует таблицу перекрестным соединением (декартовым произведением) двух таблиц: ~%% $users = DB::table('sizes') ->crossJoin('colours') ->get(); ~%% %% **Сложные условия объединения** Вы можете указать более сложные условия для объединения. Для начала передайте замыкание вторым аргументом метода %%join()%%. Замыкание будет получать объект %%(t)JoinClause%%, позволяя вам указать условия для объединения: %% DB::table('users') ->join('contacts', function ($join) { $join->on('users.id', '=', 'contacts.user_id')->orOn(...); }) ->get(); %% Если вы хотите использовать стиль "where" для ваших объединений, то можете использовать для этого методы %%where()%% и %%orWhere()%%. Вместо сравнения двух столбцов эти методы будут сравнивать столбец и значение: %% DB::table('users') ->join('contacts', function ($join) { $join->on('users.id', '=', 'contacts.user_id') ->where('contacts.user_id', '>', 5); }) ->get(); %% == Слияние (%%(t)UNION%%) == Конструктор запросов позволяет создавать слияния двух запросов вместе. Например, вы можете создать начальный запрос и с помощью метода %%union()%% слить его со вторым запросом: %% $first = DB::table('users') ->whereNull('first_name'); $users = DB::table('users') ->whereNull('last_name') ->union($first) ->get(); %% .(alert) Также существует метод %%unionAll()%% с аналогичными параметрами. == Условия %%(t)WHERE%% == **Простые условия %%(t)WHERE%%** Для добавления в запрос условий %%(t)where%% используйте метод %%where()%% на экземпляре конструктора запросов. Самый простой вызов %%where()%% требует три аргумента. Первый - имя столбца. Второй - оператор (любой из поддерживаемых базой данных). Третий - значение для сравнения со столбцом. Например, вот запрос, проверяющий равенство значения столбца "votes" и 100: %% $users = DB::table('users')->where('votes', '=', 100)->get(); %% Для удобства, если вам необходимо просто проверить равенство значения столбца и данного значения, вы можете передать значение сразу вторым аргументом метода %%where()%%: %% $users = DB::table('users')->where('votes', 100)->get(); %% Разумеется, вы можете использовать различные другие операторы при написании условия %%(t)where%%: %% $users = DB::table('users') ->where('votes', '>=', 100) ->get(); $users = DB::table('users') ->where('votes', '<>', 100) ->get(); $users = DB::table('users') ->where('name', 'like', 'T%') ->get(); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) В функцию %%where()%% также можно передать массив условий: ~%% $users = DB::table('users')->where([ ['status', '=', '1'], ['subscribed', '<>', '1'], ])->get(); ~%% %% **Условия //ИЛИ//** Вы можете сцепить вместе условия %%(t)where%%, а также условия %%(t)or%% в запросе. Метод %%orWhere()%% принимает те же аргументы, что и метод %%where()%%: %% $users = DB::table('users') ->where('votes', '>', 100) ->orWhere('name', 'John') ->get(); %% **Дополнительные условия %%(t)WHERE%%** **В интервале** Метод %%whereBetween()%% проверяет, что значения столбца находится **в** указанном интервале: %% $users = DB::table('users') ->whereBetween('votes', [1, 100])->get(); %% **Вне интервала** Метод %%whereNotBetween()%% проверяет, что значения столбца находится **вне** указанного интервала: %% $users = DB::table('users') ->whereNotBetween('votes', [1, 100]) ->get(); %% **Фильтрация по совпадению с массивом значений** Метод %%whereIn()%% проверяет, что значения столбца содержатся в данном массиве: %% $users = DB::table('users') ->whereIn('id', [1, 2, 3]) ->get(); %% Метод %%whereNotIn()%% проверяет, что значения столбца **не** содержатся в данном массиве: %% $users = DB::table('users') ->whereNotIn('id', [1, 2, 3]) ->get(); %% **Поиск неустановленных значений (%%(t)NULL%%)** Метод %%whereNull()%% проверяет, что значения столбца равны %%NULL%%: %% $users = DB::table('users') ->whereNull('updated_at') ->get(); %% Метод %%whereNotNull()%% проверяет, что значения столбца не равны %%NULL%%: %% $users = DB::table('users') ->whereNotNull('updated_at') ->get(); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) **whereDate / whereMonth / whereDay / whereYear** Метод %%whereDate()%% служит для сравнения значения столбца с датой: ~%% $users = DB::table('users') ->whereDate('created_at', '2016-12-31') ->get(); ~%% Метод %%whereMonth()%% служит для сравнения значения столбца с месяцем в году: ~%% $users = DB::table('users') ->whereMonth('created_at', '12') ->get(); ~%% Метод %%whereDay()%% служит для сравнения значения столбца с днём месяца: ~%% $users = DB::table('users') ->whereDay('created_at', '31') ->get(); ~%% Метод %%whereYear()%% служит для сравнения значения столбца с указанным годом: ~%% $users = DB::table('users') ->whereYear('created_at', '2016') ->get(); ~%% %% %%(DOCNEW 5.0=5d10040a981deee82c0fde0e8e5d2ffc49eaaecb 8.02.2016 18:09:11) **Динамические условия %%(t)WHERE%%** Вы можете использовать даже "динамические" условия %%(t)where%% для гибкого построения операторов, используя магические методы: ~%% $admin = DB::table('users')->whereId(1)->first(); $john = DB::table('users') ->whereIdAndEmail(2, 'john@doe.com') ->first(); $jane = DB::table('users') ->whereNameOrAge('Jane', 22) ->first(); ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) **whereColumn** Для проверки на совпадение двух столбцов можно использовать метод %%whereColumn()%%: ~%% $users = DB::table('users') ->whereColumn('first_name', 'last_name') ->get(); ~%% В метод также можно передать оператор сравнения: ~%% $users = DB::table('users') ->whereColumn('updated_at', '>', 'created_at') ->get(); ~%% В метод %%whereColumn()%% также можно передать массив с несколькими условиями. Эти условия будут объединены оператором %%(t)AND%%: ~%% $users = DB::table('users') ->whereColumn([ ['first_name', '=', 'last_name'], ['updated_at', '>', 'created_at'] ])->get(); ~%% %% === Группировка условий === Иногда вам нужно сделать выборку по более сложным параметрам, таким как "существует ли" или вложенная группировка условий. Конструктор запросов Laravel справится и с такими запросами. Для начала посмотрим на пример группировки условий в скобках: %% DB::table('users') ->where('name', '=', 'John') ->orWhere(function ($query) { $query->where('votes', '>', 100) ->where('title', '<>', 'Admin'); }) ->get(); %% Как видите, передав замыкание в метод %%orWhere()%%, мы дали конструктору запросов команду, начать группировку условий. Замыкание получит экземпляр конструктора запросов, который вы можете использовать для задания условий, поместив их в скобки. Приведённый пример выполнит такой SQL-запрос: %%(sql) select * from users where name = 'John' or (votes > 100 and title <> 'Admin') %% === Проверка на существование === Метод %%whereExists()%% позволяет написать SQL-условие %%(t)where exists%%. Метод %%whereExists()%% принимает в качестве аргумента замыкание, которое получит экземпляр конструктора запросов, позволяя вам определить запрос для помещения в условие "exists": %% DB::table('users') ->whereExists(function ($query) { $query->select(DB::raw(1)) ->from('orders') ->whereRaw('orders.user_id = users.id'); }) ->get(); %% Этот пример выполнит такой SQL-запрос: %%(sql) select * from users where exists ( select 1 from orders where orders.user_id = users.id ) %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) === JSON фильтрация (%%(t)WHERE%%) === Laravel также поддерживает запросы для столбцов типа JSON в тех БД, которые поддерживают тип столбцов JSON. На данный момент это MySQL 5.7 и Postgres. Для запроса JSON столбца используйте оператор %%(t)->%% : ~%% $users = DB::table('users') ->where('options->language', 'en') ->get(); $users = DB::table('users') ->where('preferences->dining->meal', 'salad') ->get(); ~%% %% == Упорядочивание, группировка, предел и смещение == **orderBy** Метод %%orderBy()%% позволяет вам отсортировать результат запроса по заданному столбцу. Первый аргумент метода %%orderBy()%% - столбец для сортировки по нему, а второй - задаёт направление сортировки и может быть либо %%(t)asc%%, либо %%(t)desc%%: %% $users = DB::table('users') ->orderBy('name', 'desc') ->get(); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) **latest / oldest** Методы %%latest()%% и %%oldest()%% позволяют легко отсортировать результаты по дате. По умолчанию выполняется сортировка по столбцу %%(t)created_at%%. Или вы можете передать имя столбца для сортировки по нему: ~%% $user = DB::table('users') ->latest() ->first(); ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) **inRandomOrder** Для сортировки результатов запроса в случайном порядке можно использовать метод %%inRandomOrder()%%. Например, вы можете использовать этот метод для выбора случайного пользователя: ~%% $randomUser = DB::table('users') ->inRandomOrder() ->first(); ~%% %% **groupBy / having / havingRaw** Методы %%groupBy()%% и %%having()%% используются для группировки результатов запроса. Сигнатура метода %%having()%% аналогична методу %%where()%%: %% $users = DB::table('users') ->groupBy('account_id') ->having('account_id', '>', 100) ->get(); %% Метод %%havingRaw()%% используется для передачи сырой строки в условие %%(t)having%%. Например, мы можем найти все филиалы с объёмом продаж выше $2,500: %% $users = DB::table('orders') ->select('department', DB::raw('SUM(price) as total_sales')) ->groupBy('department') ->havingRaw('SUM(price) > 2500') ->get(); %% **skip / take** Для ограничения числа возвращаемых результатов из запроса или для пропуска заданного числа результатов в запросе используются методы %%skip()%% и %%take()%%: %% $users = DB::table('users')->skip(10)->take(5)->get(); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) Или вы можете использовать методы %%limit()%% и %%offset()%%: ~%% $users = DB::table('users') ->offset(10) ->limit(5) ->get(); ~%% %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51, 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) == Условное применение условий == Иногда необходимо применять условие к запросу, только если выполняется какое-то другое условие. Например, выполнять оператор %%where%%, только если нужное значение есть во входящем запросе. Это можно сделать с помощью метода %%when()%%: ~%% $role = $request->input('role'); $users = DB::table('users') ->when($role, function ($query) use ($role) { return $query->where('role_id', $role); }) ->get(); ~%% Метод %%when()%% выполняет данное замыкание, только когда первый параметр равен %%true%%. Если первый параметр равен %%false%%, то замыкание не будет выполнено. %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) Вы можете передать ещё одно замыкание третьим параметром метода %%when()%%. Это замыкание будет выполнено, если первый параметр будет иметь значение %%false%%. Для демонстрации работы этой функции мы используем её для настройки сортировки по умолчанию для запроса: ~%% $sortBy = null; $users = DB::table('users') ->when($sortBy, function ($query) use ($sortBy) { return $query->orderBy($sortBy); }, function ($query) { return $query->orderBy('name'); }) ->get(); ~%% %% == Вставка (%%(t)INSERT%%) == Конструктор запросов предоставляет метод %%insert()%% для вставки записей в таблицу БД. Метод %%insert()%% принимает массив имён столбцов и значений: %% DB::table('users')->insert( ['email' => 'john@example.com', 'votes' => 0] ); %% Вы можете вставить в таблицу сразу несколько записей одним вызовом %%insert()%%, передав ему массив массивов, каждый из которых - строка для вставки в таблицу: %% DB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]); %% **Автоинкрементные ID** Если в таблице есть автоинкрементный ID, используйте метод %%insertGetId()%% для вставки записи и получения её ID: %% $id = DB::table('users')->insertGetId( ['email' => 'john@example.com', 'votes' => 0] ); %% .(alert) При использовании метода %%insertGetId()%% для PostgreSQL автоинкрементное поле должно иметь имя %%id%%. Если вы хотите получить ID из другого поля таблицы, вы можете передать его имя вторым аргументом. == Обновление (%%(t)UPDATE%%) == Разумеется, кроме вставки записей в БД конструктор запросов может и изменять существующие строки с помощью метода %%update()%%. Метод %%update()%%, как и метод %%insert()%%, принимает массив столбцов и пар значений, содержащих столбцы для обновления. Вы можете ограничить запрос %%update()%% условием %%where()%%: %% DB::table('users') ->where('id', 1) ->update(['votes' => 1]); %% %%(DOCNEW 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51) === Обновление JSON-столбцов === При обновлении JSON-столбцов используйте синтаксис %%->%% для обращения к нужному ключу в JSON-объекте. Эта операция поддерживается только в БД, поддерживающих JSON-столбцы: ~%% DB::table('users') ->where('id', 1) ->update(['options->enabled' => true]); ~%% %% === Increment и Decrement === Конструктор запросов предоставляет удобные методы для увеличения и уменьшения значений заданных столбцов. Это просто более выразительный и краткий способ по сравнению с написанием оператора %%(t)update%% вручную. Оба метода принимают один обязательный аргумент - столбец для изменения. Второй аргумент может быть передан для указания, на какую величину необходимо изменить значение столбца: %% DB::table('users')->increment('votes'); DB::table('users')->increment('votes', 5); DB::table('users')->decrement('votes'); DB::table('users')->decrement('votes', 5); %% Вы также можете указать дополнительные поля для изменения: %% DB::table('users')->increment('votes', 1, ['name' => 'John']); %% == Удаление (%%(t)DELETE%%) == Конструктор запросов предоставляет метод %%delete()%% для удаления записей из таблиц. Вы можете ограничить оператор %%delete()%%, добавив условие %%where()%% перед его вызовом: %% DB::table('users')->delete(); DB::table('users')->where('votes', '>', 100)->delete(); %% Если вы хотите очистить таблицу (усечение), удалив все строки и обнулив счётчик ID, используйте метод %%truncate()%%: %% DB::table('users')->truncate(); %% .(tl_note) Усечение таблицы аналогично удалению всех её записей, а также сбросом счётчика //autoincrement//-полей. - //прим. пер.// == Пессимистическая блокировка == В конструкторе запросов есть несколько функций, которые помогают делать "пессимистическую блокировку" (//pessimistic locking//) для ваших операторов SELECT. Для запуска оператора SELECT с "разделяемой блокировкой" вы можете использовать в запросе метод %%sharedLock()%%. Разделяемая блокировка предотвращает изменение выбранных строк до конца транзакции: %% DB::table('users')->where('votes', '>', 100)->sharedLock()->get(); %% Или вы можете использовать метод %%lockForUpdate()%%. Блокировка "для изменения" предотвращает изменение строк и их выбор другими разделяемыми блокировками: %% DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get(); %%