Вычисляемые поля ORM в Bitrix D7: агрегаты и функции SQL в запросе
Зачем смешивать SQL с ORM
Иногда в одном запросе нужно и отфильтровать живые столбцы сущности, и получить производные значения вида суммы или крайней даты. В D7 это делают через массив runtime у getList(): туда добавляют поля-представления, которые не живут как отдельные колонки в таблице, но становятся частью отправляемого SQL.
Плейсхолдер и список полей для подстановки
Класс \Bitrix\Main\ORM\Fields\ExpressionField (в старших проектах встречается устаревшее совместимое имя Entity\ExpressionField) принимает машинное имя псевдополя, шаблон SQL и имена столбцов карты таблицы, которые платформа аккуратно экранирует и подставляет вместо %s.
Самый частый паттерн: MIN и MAX без группировки
На короткой выборке по активным пользователям можно сразу узнать граничные значения календарного поля, не вытягивая все строки в PHP:
$userBounds = \Bitrix\Main\UserTable::getList([
'filter' => ['=ACTIVE' => 'Y'],
'runtime' => [
new \Bitrix\Main\ORM\Fields\ExpressionField(
'BIRTHDAY_MIN',
'MIN(%s)',
['PERSONAL_BIRTHDAY']
),
new \Bitrix\Main\ORM\Fields\ExpressionField(
'BIRTHDAY_MAX',
'MAX(%s)',
['PERSONAL_BIRTHDAY']
),
],
'select' => ['BIRTHDAY_MIN', 'BIRTHDAY_MAX'],
]);
$edgeDates = $userBounds->fetch();Размер результата — одна строка с двумя псевдостолбцами; платформа знает типы и приведёт календарные поля к объекту \Bitrix\Main\Type\Date там, где это предусмотрено картой UserTable.
Что ещё удобно выражать тем же способом
На практике к набору SUM(%s), COUNT(*), LENGTH(%s), приведение регистра LOWER(%s) или конкатенацию двух столбцов подключают, когда хотят не дублировать текст SQL в строковых константах вне объектной обёртки ядра. Для простых производных между двумя известными полями стоит сохранять читаемый шаблон и список полей синхронно с обновлениями таблицы, иначе рефакторинг мапперов затронет несколько точек приложения.
Ограничения и производительность
- «Тяжёлые» агрегаты по большим наборам лучше сопровождать осмысленным
filter, индексами по столбцам из выражений и пониманием того, нужна ли здесь именно строка результата в стиле ORM или отдельный «сырой» отчёт. - Если в одном запросе несколько конфликтующих
GROUP BYна уровне логики, проще вернуться к явному тексту черезQueryили разбить сценарий на два узких запроса, чем плотить недокументируемые вложения в runtime. - Всегда проверяйте SQL на копии: конструктор синтаксиса не заменяет профилировщик базы под ваш профиль данных.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии