При разработке запросов в платформе 1С:Предприятие часто возникает задача отбора строк, где реквизитом может выступать как конечный элемент, так и группа справочника. Типичная ситуация: в строках табличной части указаны папки или элементы справочника (например, группы контрагентов), а в качестве параметра запроса &НашКонтрагент передается конкретный подчиненный элемент.
Попытка написать условие вида (&НашКонтрагент) В ИЕРАРХИИ (Таблица.Контрагент) приводит к синтаксической ошибке. Выясним причину такого поведения платформы и разберем несколько проверенных вариантов реализации этой логики.
Оператор В ИЕРАРХИИ в языке запросов 1С работает строго «сверху вниз». Его синтаксис жестко регламентирован:
Платформа транслирует оператор В ИЕРАРХИИ в поиск по иерархическим индексам для фиксированного списка предков. Вычислять цепочку родителей «снизу вверх» динамически для каждой строки таблицы платформа через этот оператор не умеет. Разберем по шагам практические способы обойти это ограничение.
Если проверяемый элемент-параметр известен заранее во встроенном языке до выполнения запроса, самым производительным решением будет собрать массив всех его родителей и передать в запрос обычное условие вхождения в список.
Посмотрим на пример кода сбора всех вышестоящих групп:
МассивРодителей = Новый Массив;
МассивРодителей.Добавить(НашКонтрагент);
ТекущийРодитель = НашКонтрагент.Родитель;
Пока ЗначениеЗаполнено(ТекущийРодитель) Цикл
МассивРодителей.Добавить(ТекущийРодитель);
ТекущийРодитель = ТекущийРодитель.Родитель;
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Задачи.Ссылка КАК Задача,
| Задачи.Контрагент КАК Контрагент
|ИЗ
| Документ.ЗадачиПользователя.Контрагенты КАК Задачи
|ГДЕ
| Задачи.Контрагент В (&РодителиЭлемента)";
Запрос.УстановитьПараметр("РодителиЭлемента", МассивРодителей);
РезультатЗапроса = Запрос.Выполнить();
Преимущества данного подхода:
В (&РодителиЭлемента) выполняется на уровне СУБД максимально быстро по простому индексу.Если справочник имеет фиксированное небольшое число уровней вложенности (в свойствах метаданных включено Ограничивать количество уровней), можно развернуть проверку через условие ИЛИ.
Рассмотрим пример условия в секции ГДЕ:
ГДЕ
ЗадачиПользователяКонтрагенты.Контрагент = ВЫРАЗИТЬ(&НашКонтрагент КАК Справочник.Контрагенты)
ИЛИ ЗадачиПользователяКонтрагенты.Контрагент = ВЫРАЗИТЬ(&НашКонтрагент КАК Справочник.Контрагенты).Родитель
ИЛИ ЗадачиПользователяКонтрагенты.Контрагент = ВЫРАЗИТЬ(&НашКонтрагент КАК Справочник.Контрагенты).Родитель.Родитель
Особенности и ограничения:
Родитель порождает неявное левое соединение (LEFT JOIN) в итоговом SQL-запросе.Когда запрос должен быть полностью автономен (например, используется в динамическом списке или схеме компоновки данных), применяется алгоритм транзитивного замыкания иерархии во временных таблицах.
Разберем логику построения:
Ссылка - Родитель.Элемент - ВсеРодители.Посмотрим на структуру связывания в запросе:
ВЫБРАТЬ
ЗадачиПользователяКонтрагенты.Ссылка КАК ДокументСсылка,
ЗадачиПользователяКонтрагенты.Контрагент КАК Контрагент
ИЗ
Документ.ЗадачиПользователя.Контрагенты КАК ЗадачиПользователяКонтрагенты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Иерархия КАК Иерархия
ПО ЗадачиПользователяКонтрагенты.Контрагент = Иерархия.Родитель
И Иерархия.Ссылка = &НашКонтрагент
Этот метод универсален для чистого SQL и автономных запросов, однако требует формирования дополнительной временной таблицы иерархии перед выполнением основной выборки.