Звезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активна
 

Методы выборки построителя запросов Yii2

Методы выборки

[[yii\db\Query]] предоставляет целый набор методов для разных вариантов выборки:

  • [[yii\db\Query::all()|all()]]: возвращает массив строк, каждая из которых это ассоциативный массив пар ключ-значение.
  • [[yii\db\Query::one()|one()]]: возвращает первую строку запроса.
  • [[yii\db\Query::column()|column()]]: возвращает первый столбец результата.
  • [[yii\db\Query::scalar()|scalar()]]: возвращает скалярное значение первого столбца первой строки результата.
  • [[yii\db\Query::exists()|exists()]]: возвращает значение указывающее, что выборка содержит результат.
  • [[yii\db\Query::count()|count()]]: возвращает результат COUNT запроса.
  • Другие методы агрегирования запросов, включая [[yii\db\Query::sum()|sum($q)]], [[yii\db\Query::average()|average($q)]], [[yii\db\Query::max()|max($q)]], [[yii\db\Query::min()|min($q)]]. Параметр $q обязателен для этих методов и могут содержать либо имя столбца, либо выражение БД.


Например,

// SELECT `id`, `email` FROM `user`
$rows = (new \yii\db\Query())
    ->select(['id', 'email'])
    ->from('user')
    ->all();
    
// SELECT * FROM `user` WHERE `username` LIKE `%test%`
$row = (new \yii\db\Query())
    ->from('user')
    ->where(['like', 'username', 'test'])
    ->one();

Note: метод [[yii\db\Query::one()|one()]] вернёт только первую строку результата запроса. Он НЕ добавляет LIMIT 1 в генерируемый SQL. Это хорошо и предпочтительно если вы знаете, что запрос вернёт только одну или несколько строк данных (например, при запросе по первичному ключу). Однако, если запрос потенциально может вернут много строк данных, вы должны вызвать limit(1) для повышения производительности, Например, (new \yii\db\Query())->from('user')->limit(1)->one().

Все методы выборки могут получать необязательный параметр $db, представляющий [[yii\db\Connection|соединение с БД]], которое должно использоваться, чтобы выполнить запрос к БД. Если вы упускаете этот параметр, будет использоваться компонент приложения $db. Ниже приведён ещё один пример использования метода [[yii\db\Query::count()|count()]]:

// executes SQL: SELECT COUNT(*) FROM `user` WHERE `last_name`=:last_name
$count = (new \yii\db\Query())
    ->from('user')
    ->where(['last_name' => 'Smith'])
    ->count();

При вызове методов выборки [[yii\db\Query]], внутри на самом деле проводится следующая работа:

  • Вызывается [[yii\db\QueryBuilder]] для генерации SQL запроса на основе текущего [[yii\db\Query]];
  • Создаёт объект [[yii\db\Command]] с сгенерированным SQL запросом;
  • Вызывается выбирающий метод (например [[yii\db\Command::queryAll()|queryAll()]]) из [[yii\db\Command]] для выполнения SQL запроса и извлечения данных.

Иногда вы можете захотеть увидеть или использовать SQL запрос построенный из объекта [[yii\db\Query]]. Этой цели можно добиться с помощью следующего кода:

$command = (new \yii\db\Query())
    ->select(['id', 'email'])
    ->from('user')
    ->where(['last_name' => 'Smith'])
    ->limit(10)
    ->createCommand();
    
// показать SQL запрос
echo $command->sql;
// показать привязываемые параметры
print_r($command->params);

// возвращает все строки запроса
$rows = $command->queryAll();

Индексация результатов запроса

При вызове [[yii\db\Query::all()|all()]] возвращается массив строк индексированный последовательными целыми числами. Иногда вам может потребоваться индексировать его по-другому, например, сделать индекс по указанному столбцу или значением выражения. Вы можете реализовать такое поведение через вызов [[yii\db\Query::indexBy()|indexBy()]] перед вызовом [[yii\db\Query::all()|all()]].

// возвращает [100 => ['id' => 100, 'username' => '...', ...], 101 => [...], 103 => [...], ...]
$query = (new \yii\db\Query())
    ->from('user')
    ->limit(10)
    ->indexBy('id')
    ->all();

Для индексации по значению выражения, передайте анонимную функцию в метод [[yii\db\Query::indexBy()|indexBy()]]:

$query = (new \yii\db\Query())
    ->from('user')
    ->indexBy(function ($row) {
        return $row['id'] . $row['username'];
    })->all();

Анонимная функция должна принимать параметр $row, который содержит текущую строку запроса и должна вернуть скалярное значение, которое будет использоваться как значение индекса для текущей строки.

Пакетная выборка

При работе с большими объемами данных, методы на подобие [[yii\db\Query::all()]] не подходят, потому что они требуют загрузки всех данных в память. Чтобы сохранить требования к памяти минимальными, Yii предоставляет поддержку так называемых пакетных выборок. Пакетная выборка делает возможным курсоры данных и выборку данных пакетами.

Пакетная выборка может использоваться следующим образом:

use yii\db\Query;

$query = (new Query())
    ->from('user')
    ->orderBy('id');

foreach ($query->batch() as $users) {
    // $users это массив из 100 или менее строк из таблицы пользователей
}

// или если вы хотите перебрать все строки по одной
foreach ($query->each() as $user) {
    // $user представляет одну строку из выборки
}

Метод [[yii\db\Query::batch()]] и [[yii\db\Query::each()]] возвращает объект [[yii\db\BatchQueryResult]], который реализует интерфейс Iterator и может использоваться в конструкции foreach. Во время первой итерации будет выполнен SQL запрос к базе данных. Данные будут выбираться пакетами в следующих итерациях. По умолчанию, размер пакета имеет размер 100, то есть при каждой выборке будет выбираться по 100 строк. Вы можете изменить размер пакета, передав первый параметр в метод batch() или each().

По сравнению с [[yii\db\Query::all()]], пакетная выборка загружает только по 100 строк данных за раз в память. Если вы обрабатываете данные и затем сразу выбрасываете их, пакетная выборка может помочь уменьшить использование памяти.

Если указать индексный столбец через [[yii\db\Query::indexBy()]], в пакетной выборке индекс будет сохранятся. Например,

$query = (new \yii\db\Query())
    ->from('user')
    ->indexBy('username');

foreach ($query->batch() as $users) {
    // $users индексируется по столбцу "username"
}

foreach ($query->each() as $username => $user) {
    // ...
}

Заберите ссылку на статью к себе, чтобы потом легко её найти ;)

Выберите, то, чем пользуетесь чаще всего:

Спасибо за внимание, оставайтесь на связи! Ниже ссылка на форум и обсуждение ; )


Обсудить эту статью

INFO: Вы отправляете сообщение как 'Гость'