git 494c1c8efe455d80d8b4c49c5b2bf5bf3832ca77
- Введение
- Получение результатов
- Выборка данных (Selects)
- Объединение таблиц (Joins)
- Объединение результата запросов (Unions)
- Условия отбора (Where Clauses)
- Сортировка, Группировка, Лимит, Отступ (Ordering, Grouping, Limit, & Offset)
- Вставка (Inserts)
- Обновление (Updates)
- Удаление (Deletes)
- Пессимистичная блокировка (Pessimistic Locking)
Конструктор запросов Query Builder предоставляет удобный, выразительный интерфейс для создания и выполнения запросов к базе данных. Он может использоваться для выполнения большинства типов операций и работает со всеми поддерживаемыми СУБД.
Примечание: конструктор запросов Laravel использует средства PDO для защиты вашего приложения от SQL-инъекций. Нет необходимости экранировать строки перед их передачей в запрос.
Для выполнения запроса используйте метод table фасада DB. Метод возвращает объект конструктора запросов для заданной таблицы, который позволяет строить цепочки для добавления условий выборки и в итоге получить результат. В приведенном примере мы просто получаем все строки из таблицы:
<?php
namespace App\Http\Controllers;
use DB;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show a list of all of the application's users.
*
* @return Response
*/
public function index()
{
$users = DB::table('users')->get();
return view('user.index', ['users' => $users]);
}
}
Подобно запросам на чистом SQL (raw queries) метод get возвращает массив результатов, где каждый результат - это объект PHP StdClass. Вы можете получить значения каждого поля через свойства объекта:
foreach ($users as $user) {
echo $user->name;
}
Если вы хотите получить одну строку из таблицы, то используйте метод first. Метод вернет один объект типа StdClass:
$user = DB::table('users')->where('name', 'John')->first();
echo $user->name;
Если из этой одной строки требуется только одна колонка, то используйте метод value. Метод вернет значение этого поля:
$email = DB::table('users')->where('name', 'John')->value('email');
Если требуется работать с тысячами строк, то обратите внимание на метод chunk. Метод получает данные маленькими "частями" ("chunk") и обрабатывает их в функции-замыкании. Метод очень полезен для записи Artisan commands тысяч строк. Например, давайте работать со всей таблицей users частями по 100 записей:
DB::table('users')->chunk(100, function($users) {
foreach ($users as $user) {
//
}
});
Остановить отбор результатов можно, возвратив false из функции-замыкания:
DB::table('users')->chunk(100, function($users) {
// Process the records...
return false;
});
Если нужно получить массив значений одного столбца, то используйте метод pluck. Например, получим из таблицы roles массив значений столбца title:
$titles = DB::table('roles')->pluck('title');
foreach ($titles as $title) {
echo $title;
}
Также можно задать столбец, значения которого будут ключами для возвращаемого массива:
$roles = DB::table('roles')->pluck('title', 'name');
foreach ($roles as $name => $title) {
echo $title;
}
Конструктор предоставляет разнообразные групповые методы, такие как 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');
Конечно, вам не всегда требуется выбирать все столбцы из таблицы. Используя метод 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();
Конструктор запросов умеет делать объединение таблиц. Для выполнения простого SQL "inner 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();
Для левостороннего объединения предназначен метод leftJoin. Его параметры аналогичны методу join:
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
Вы также можете определять более продвинутые условия объединения. Для начала в качестве второго аргумента задайте функцию-замыкание. Замыкание получит объект 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();
Конструктор предоставляет быстрый способ объединения двух запросов. Например, можно создать первый запрос и затем использовать метод union для объединения со вторым запросом:
$first = DB::table('users')
->whereNull('first_name');
$users = DB::table('users')
->whereNull('last_name')
->union($first)
->get();
Также доступен метод unionAll с такой же сигнатурой как у union.
Для использования конструкции where в запросе используйте метод where. Обычный вызов метода требует три аргумента. Первый - имя столбца. Второй - любой поддерживаемый СУБД оператор. Третий - значение для сравнения. Например, запрос, проверяющий, что значение столбца 'votes' равно 100:
$users = DB::table('users')->where('votes', '=', 100)->get();
Для убодства, если требуется простое сравнение на равенство, можно опустить второй аргумент:
$users = DB::table('users')->where('votes', 100)->get();
Конечно, вы можете использовать другие операторы:
$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();
В методе даже можно задавать массив условий:
$users = DB::table('users')->where([
['status','1'],
['subscribed','<>','1'],
])->get();
Вы можете присоединять условия 'where', также как и добавлять условие ИЛИ (or) в запрос. Метод orWhere принимает аргументы как и метод where:
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();
whereBetween
Метод проверяет, что значение поля находится между двух указанных значений
$users = DB::table('users')
->whereBetween('votes', [1, 100])->get();
whereNotBetween
Метод противоположен методу whereBetween:
$users = DB::table('users')
->whereNotBetween('votes', [1, 100])
->get();
whereIn / whereNotIn
Значение должно находиться в указанном массиве:
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
Значение не должно находиться в массиве:
$users = DB::table('users')
->whereNotIn('id', [1, 2, 3])
->get();
whereNull / whereNotNull
Значение поля должно быть NULL:
$users = DB::table('users')
->whereNull('updated_at')
->get();
Значение не должно быть NULL:
$users = DB::table('users')
->whereNotNull('updated_at')
->get();
Иногда требуется создать более продвинутые условия отбора, подобно "where exists" или вложенной группировке (nested parameter groupings). Конструктор запросов Laravel может это делать. Для начала взгляните на пример группировки условий внутри круглых скобок:
DB::table('users')
->where('name', '=', 'John')
->orWhere(function ($query) {
$query->where('votes', '>', 100)
->where('title', '<>', 'Admin');
})
->get();
Как видите замыкание в методе orWhere указывает конструктору начать группу условий. Замыкание получит объект запроса, который вы можете использовать для установки ограничений внутри круглых скобок. Пример выше создаст следующий SQL запрос:
select * from users where name = 'John' or (votes > 100 and title <> 'Admin')
Метод whereExists позволяет писать в запрос SQL выражение where exist. Этот метод принимает замыкание в качестве аргумента, которому будет передан объект запроса, позволяющий определить запрос для выражения "exists":
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Пример выше сформирует следующий запрос SQL:
select * from users
where exists (
select 1 from orders where orders.user_id = users.id
)
Laravel поддерживает запросы к полям с типом JSON для СУБД с поддержкой этого типа. На текущий момент это MySQL 5.7 and Postgres. Для запроса к такому полю используйте оператор ->:
$users = DB::table('users')
->where('options->language', 'en')
->get();
$users = DB::table('users')
->where('preferences->dining->meal', 'salad')
->get();
Метод orderBy позволяет сортировать результаты запроса по указанной колонке. Первый аргумент метода - колонка, по которой выполняется сортировка. Второй - направление сортировки asc or desc:
$users = DB::table('users')
->orderBy('name', 'desc')
->get();
Методы groupBy и having служат для группировки результатов запроса. Сигнатура метода having аналогична where:
$users = DB::table('users')
->groupBy('account_id')
->having('account_id', '>', 100)
->get();
Метод havingRaw нужен для установки значения выражения having в виде SQL строки. Например, найдем все отделы, где продажи превысили $2500:
$users = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > 2500')
->get();
Для ограничение числа возвращаемых значений запросом либо для пропуска первых результатов в запросе (OFFSET) используйте методы skip and take:
$users = DB::table('users')->skip(10)->take(5)->get();
Конструктор также обеспечивает метод insert для вставки записей в таблицу. Метод принимает массив пар колонка=>значение:
DB::table('users')->insert(
['email' => 'john@example.com', 'votes' => 0]
);
Для вставки более одной строки используется массив массивов:
DB::table('users')->insert([
['email' => 'taylor@example.com', 'votes' => 0],
['email' => 'dayle@example.com', 'votes' => 0]
]);
Если таблица имеет автоинкрементируемый столбец, то для получения значения этого столбца для вставленной записи используется метод insertGetId:
$id = DB::table('users')->insertGetId(
['email' => 'john@example.com', 'votes' => 0]
);
Примечание: Когда используется PostgreSQL метод ожидает, что такой столбец называется
id. Если требуется получать значение из другого "sequence", то его имя нужно указывать во втором аргументе методаinsertGetId
Конструктор обеспечивает поддержку обновления записей через метод update. Метод аналогично методу вставки принимает массив пар столбец=>значение. Для ограничения обновляемых строк используйте метод where:
DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
Методы increment / decrement позволяют увеличивать/уменьшать значение стобца. Методы являются сокращениями для метода 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']);
Удаление всех строк из таблицы:
DB::table('users')->delete();
Удаление строк, соответствующих условию:
DB::table('users')->where('votes', '<', 100)->delete();
Удаление всех строк и сброс автоинкремента (очистка таблицы):
DB::table('users')->truncate();
Для использования блокировки "shared lock" предназначен метод sharedLock. Метод предохраняет выбранные строки от изменения до завершения вашей транзакции:
DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
Другой вариант использовать метод lockForUpdate. Блокировка "for update" предохраняет выбранные строки от изменения и от установки блокировки "shared lock":
DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();