Запросы к базе данных
# Введение
Query Builder - конструктор запросов - предоставляет удобный, выразительный интерфейс для создания и выполнения запросов к базе данных. Он может использоваться для выполнения большинства типов операций и работает со всеми подерживаемыми СУБД.
Примечание: конструктор запросов использует средства PDO для защиты вашего приложения от SQL-инъекций. Нет необходимости экранировать строки перед их передачей в запрос.
# Получение результатов
# Получение всех строк из таблицы
Давайте получим все записи из таблицы при помощи метода get
. Для этого используем метод table
из фасада Db
, который вернет экземпляр конструктора запросов, позволяя Вам добавлять остальные методы друг за другом и затем, наконец, получить результат:
$users = Db::table('users')->get();
Как и сырые SQL-запросы, метод get
возвращает массив с результатами, элементы которого являются экземплярами объекта PHP stdClass
. Вы можете получить доступ к значению каждого столбца, обратившись к нему как свойству объекта:
foreach ($users as $user) {
echo $user->name;
}
# Получение одной записи
$user = Db::table('users')->where('name', 'John')->first();
echo $user->name;
# Получение одного поля из записей
$email = Db::table('users')->where('name', 'John')->pluck('email');
# Обработка большого объема данных
Если Вам нужно обработать тысячи записей базы данных, используйте метод chunk
, который извлекает несколько строк за раз и передает их в Closure
для обработки. Пример:
Db::table('users')->chunk(100, function($users) {
foreach ($users as $user) {
//
}
});
Вы можете остановить извлечение строк при помощи return false
в Closure
:
Db::table('users')->chunk(100, function($users) {
// Process the records...
return false;
});
# Получение списка всех значений одного поля
Используйте метод 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;
}
# Аггрегатные функции
Конструктор запросов содержит множество аггрегатных методов, таких как count
, max
, min
, avg
и sum
.
$users = Db::table('users')->count();
$price = Db::table('orders')->max('price');
Вы также можете комбинировать эти методы с другими:
$price = Db::table('orders')
->where('is_finalized', 1)
->avg('price');
# Выборки (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();
# Использование сырого выражения
Используйте метод Db::raw
, чтобы добавить уже готовое SQL-выражение в ваш запрос:
$users = Db::table('users')
->select(Db::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
# Объединения (JOIN)
# Объединение типа INNER 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();
# Объединение типа LEFT JOIN
$users = Db::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
# Расширенное объединение
Вы можете указать более сложные условия:
Db::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();
Внутри join() можно использовать 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
с аналогичными параметрами.
# Выражения с WHERE
# Простой пример
$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('votes', '>', 100)
->orWhere('name', 'John')
->get();
# Фильтрация по интервалу значений
$users = Db::table('users')
->whereBetween('votes', [1, 100])->get();
$users = Db::table('users')
->whereNotBetween('votes', [1, 100])
->get();
# Фильтрация по совпадению с массивом значений
$users = Db::table('users')
->whereIn('id', [1, 2, 3])
->get();
$users = Db::table('users')
->whereNotIn('id', [1, 2, 3])
->get();
# Поиск неустановленных значений (NULL)
$users = Db::table('users')
->whereNull('updated_at')
->get();
$users = Db::table('users')
->whereNotNull('updated_at')
->get();
# Сложные выражения с WHERE
# Группировка условий
Иногда вам нужно сделать выборку по более сложным параметрам, таким как "существует ли" или вложенная группировка условий. Конструктор запросов справится и с этим:
Db::table('users')
->where('name', '=', 'John')
->orWhere(function ($query) {
$query->where('votes', '>', 100)
->where('title', '<>', 'Admin');
})
->get();
Команда выше выполнит такой SQL:
select * from users where name = 'John' or (votes > 100 and title <> 'Admin')
# Проверка на существование
Db::table('users')
->whereExists(function ($query) {
$query->select(Db::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Эта команда выше выполнит такой запрос:
select * from users where exists (
select 1 from orders where orders.user_id = users.id
)
# Сортировка, группировка, ограничение и смещение
# Сортировка
$users = Db::table('users')
->orderBy('name', 'desc') // `asc` или `desc`
->get();
# Группировка
$users = Db::table('users')
->groupBy('account_id')
->having('account_id', '>', 100) // также как в where
->get();
$users = Db::table('orders')
->select('department', Db::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > 2500')
->get();
# Ограничение и смещение
$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]
]);
# Вставка записи и получение её нового ID
Если таблица имеет автоинкрементный индекс, то можно использовать метод insertGetId
для вставки записи и получения её порядкового номера:
$id = Db::table('users')->insertGetId(
['email' => 'john@example.com', 'votes' => 0]
);
# Обновление (UPDATE)
# Обновление записей в таблице
Db::table('users')
->where('id', 1)
->update(['votes' => 1]);
# Увеличение или уменьшение значения поля
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']);
# Удаление (DELETE)
# Удаление всех записей
Db::table('users')->delete();
# Удаление записей из таблицы
Db::table('users')->where('votes', '<', 100)->delete();
# Очистка таблицы
Db::table('users')->truncate();
# Блокирование (lock) данных
# SELECT с 'shared lock':
Db::table('users')->where('votes', '>', 100)->sharedLock()->get();
# SELECT с 'lock for update':
Db::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
# Кэширование запросов
Вы можете легко закэшировать запрос при помощи методов remember
или rememberForever
:
$users = Db::table('users')->remember(10)->get();
В этом примере результаты выборки будут сохранены в кэше на 10 минут. В течении этого времени данный запрос не будет отправляться к СУБД - вместо этого результат будет получен из системы кэширования, указанного по умолчанию в вашем файле настроек.