Работать будем с тремя таблицами:
CITYZEN — гражданин
| id |
| name |
| city_id |
| responsible(1- ответственный, 0-безответсвенные) |
| id |
| name |
| city_type_id |
| id |
| name |

SQL на создание таблиц можете найти тут
На их основе я сгенерировал 3 ORM-класса: CityzenTable, CityTable и CityTypeTable, на основе этой инструкции
Задача 1. Получить табличку из ответственных граждан: имя гражданина , название города гражданина и название типа города.
В SQL запрос выглядел бы так:
SELECT u.name as cityzen_name, с.name as city_name, ct.name as city_type_name FROM CITYZEN u LEFT JOIN CITY с on u.city_id = с.id LEFT JOIN CITY_TYPE ct on ct.id = с.city_type_id WHERE u.responsible = 1
Для построения запроса будем использовать класс \Bitrix\Main\Entity\Query.
Работать с ним интуитивно понятно.
<?php
use \Bitrix\Main\Entity\Query;
//Создаем экземпляр класса
//Аргумент в конструкторе класса Query - это сущность, которая соответсвует таблице в секциии FROM
$query = new \Bitrix\Main\Entity\Query(CityzenTable::getEntity());
//вынес имя таблиц в переменные , она пригодятся нам несколько раз
$cityTableName = 'CITY';
$cityzenTableName = 'CITYZEN';
$cityTypeTableName = 'CITY_TYPE';
//Чтобы сделать сложный запрос с присоединением таблиц(left right join) можно использовать registerRuntimeField
$query->registerRuntimeField($cityTableName, [
'data_type' => CityTable::getEntity(),
'reference' => [
'=this.city_id' => 'ref.id',
],
'join_type' => "LEFT"
]
);
Рассмотрим аргументы метода registerRuntimeField:
Первый — это название поля, его мы сможем использовать далее в секциях: select и filter.
Второй аргумент массив:
data_type — указываем сущность(таблица, указанная в SQL запросе, после LEFT JOIN) которую будем джойнить
reference — указываем способ связывания this указывает на сущность CityzenTable , ref на сущность указанную в data_type — CityTable
join_type — тип присоединения таблицы Возможные значения: LEFT(по умолчанию), RIGHT и INNER
по аналогии присоединяем таблицу с типами городов
$query->registerRuntimeField($cityTypeTableName, [
'data_type' => CityTypeTable::getEntity(),
'reference' => [
'=this.' . $cityTableName . '.city_type_id' => 'ref.id',
],
'join_type' => "LEFT"
]
);
В кусочке кода выше можно отметить, как устанавливается связь третьей таблицы ко второй. Нельзя указать просто
$cityTableName . '.city_type_id', т.к. использованиеthisобязательно!
Далее указываем секцию селект:
$query->setSelect([
'cityzen_name' => $cityzenTableName . '.name',
'city_name' => $cityTableName . '.name',
'city_type_name' => $cityTypeTableName . '.name',
]);
В результате значение имени юзера будет доступно по ключу cityzen_name, а название группы по city_name.
$query->setFilter([
$cityzenTableName . '.responsible' => 1
]);
Если возникнет необходимость ограничить выборку одним элементом, то применяем:
$query->setLimit(1);
Когда формирование запроса закончено, нужно выполнить запрос:
$dbCityzenInfo = $query->exec();
И получаем элементы выборки:
if ($resItem = $dbCityzenInfo->fetch()){
var_dump($resItem );
}
Также можно было использовать функцию getlist вместо построителя запросов. Выглядеть это будет так:
$dbCityzenInfo = CityzenTable::getList([
'select' => [
'cityzen_name' => $cityzenTableName . '.name',
'city_name' => $cityTableName . '.name',
'city_type_name' => $cityTypeTableName . '.name',
],
'runtime' => array(
$cityTableName => [
'data_type' => CityTable::getEntity(),
'reference' => [
'=this.city_id' => 'ref.id'
],
'join_type' => 'LEFT'
],
$cityTypeTableName => [
'data_type' => CityTypeTable::getEntity(),
'reference' => [
'=this.' . $cityTableName . '.city_type_id' => 'ref.id',
],
'join_type' => 'LEFT'
],
),
'filter' => [
$cityzenTableName . '.responsible' => 1
],
'limit' => 1
]);
if ($resItem = $dbCityzenInfo->fetch()){
var_dump($resItem );
}
Фактически под запросом во втором варианте скрывается запрос 1-ого варианта, т.е. функция
getlistвыступает оберткой — дополнительным слоем абстракции.
Задача 2. На основе таблицы CITYZEN получить количество всех граждан из города Уфа(id 3).
$query = new \Bitrix\Main\Entity\Query(CityzenTable::getEntity());
$query->registerRuntimeField("CNT", [
"data_type" => "integer",
"expression" => ["count(id)"]
]
)
->setSelect(['CNT'])
->setFilter([
'city_id' => 3,
])
->exec()
->fetch()['CNT'];
Хотелось бы проверить какой sql получится на выходе. Мы можем ориентироваться на результат, но в идеале хотелось бы увидеть какой код сгенерировал битрикс?
Скоро будет готова статья по отладке.
Полезный материал по сложным запросам в битрикс:


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