Как в запросе 1С сопоставить настройки родительской группы со всеми подчиненными элементами справочника?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке подсистем хранения настроек, матриц цен, скидок или прав доступа часто возникает типовая задача: в исходной таблице (например, во временной таблице или регистре сведений) правила заданы для родительских групп иерархического справочника, а в результате требуется получить плоский список, где эти настройки распространены на все дочерние элементы и подпапки. Разберем особенности работы языка запросов 1С с иерархией и рассмотрим эффективные варианты реализации такой логики.

Почему нельзя просто написать условие соединения В ИЕРАРХИИ?

Первое, что приходит на ум разработчику — связать таблицу настроек со справочником через левое соединение с условием иерархической подчиненности. Однако в языке запросов платформы 1С:Предприятие конструкция В ИЕРАРХИИ допустима только в секциях фильтрации ГДЕ или ИМЕЮЩИЕ. Использовать конструкцию вида ПО Номенклатура.Ссылка В ИЕРАРХИИ (втНастройки.Группа) синтаксис не позволяет.

Кроме того, если передавать в секцию ГДЕ большой массив групп через В ИЕРАРХИИ (&МассивГрупп), платформа на уровне СУБД выполняет разворачивание узлов во временную таблицу. При большом объеме данных и глубоком дереве это приводит к заметной нагрузке на сервер. Разберем, какими способами можно обойти данное ограничение.

Вариант 1. Соединение через цепочку родителей фиксированной глубины

Если максимальная глубина вложенности справочника заранее ограничена и невелика (например, не превышает 5–10 уровней), наиболее быстрым и простым способом будет явное сопоставление поля группы со ссылкой элемента или его вышестоящими родителями через оператор ИЛИ.

Рассмотрим пример запроса, где к таблице переданных настроек присоединяются элементы номенклатуры:


ВЫБРАТЬ
    тНастроек.ГруппаНоменклатуры КАК ГруппаНоменклатуры,
    тНастроек.Цвет КАК Цвет,
    тНастроек.Серия КАК Серия
ПОМЕСТИТЬ втНастройки
ИЗ
    &ТаблицаНастроек КАК тНастроек
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    втНастройки.ГруппаНоменклатуры КАК ГруппаНоменклатуры,
    втНастройки.Цвет КАК Цвет,
    втНастройки.Серия КАК Серия,
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    втНастройки КАК втНастройки
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО (втНастройки.ГруппаНоменклатуры = Номенклатура.Ссылка
            ИЛИ втНастройки.ГруппаНоменклатуры = Номенклатура.Родитель
            ИЛИ втНастройки.ГруппаНоменклатуры = Номенклатура.Родитель.Родитель
            ИЛИ втНастройки.ГруппаНоменклатуры = Номенклатура.Родитель.Родитель.Родитель
            ИЛИ втНастройки.ГруппаНоменклатуры = Номенклатура.Родитель.Родитель.Родитель.Родитель
            ИЛИ втНастройки.ГруппаНоменклатуры = Номенклатура.Родитель.Родитель.Родитель.Родитель.Родитель)
            И (втНастройки.Цвет = Номенклатура.Цвет)
            И (втНастройки.Серия = Номенклатура.Серия)

Обратите внимание: Каждое обращение через точку (Родитель.Родитель) платформа транслирует в неявное соединение (LEFT OUTER JOIN) с таблицей этого же справочника на уровне СУБД. При слишком большом количестве уровней план выполнения может деградировать, поэтому для глубоких деревьев лучше применять другие подходы.

Вариант 2. Разворачивание дерева «на лету» через транзитивное замыкание

Если структура иерархии произвольная, а использовать циклы на встроенном языке не хочется, можно собрать таблицу связей всех предков и потомков за несколько шагов удвоения глубины. Для этого формируется временная таблица прямых родителей, которая затем соединяется сама с собой.

  1. Помещаем во временную таблицу пары (Ссылка, Родитель) для всех непустых элементов.
  2. В цикле из 3–4 объединений запроса (ОБЪЕДИНИТЬ) соединяем полученные связи по условию Текущий.Родитель = Следующий.Ссылка. На каждом шаге глубина разворота дерева удваивается (2, 4, 8, 16 уровней).
  3. Получаем плоскую таблицу (Элемент, Предок), с которой можно выполнять стандартное точное соединение ПО ТаблицаСвязей.Предок = втНастройки.Группа.

Такой подход обеспечивает высокую скорость на стороне СУБД и не требует жесткого ограничения на число уровней иерархии.

Вариант 3. Использование механизма связей наборов данных в СКД

Система компоновки данных (СКД) содержит встроенные оптимизированные алгоритмы обхода деревьев. Если задача решается в рамках формирования отчета или выгрузки данных, мы можем использовать схему компоновки программно:

  1. Создаем набор данных — запрос к справочнику и набор данных — таблицу настроек.
  2. На вкладке Связи наборов данных настраиваем связь между родителем и дочерними элементами, установив флаг Связь по иерархии.
  3. Программно выполняем компоновку с помощью ПроцессорКомпоновкиДанных и выгружаем результат в ТаблицаЗначений. Платформа сама корректно рассчитает подчиненность элементов без написания сложных запросов.

Вариант 4. Служебный регистр сведений для денормализации иерархии

Если доступ к конфигурации открыт и подобные запросы выполняются часто, наиболее производительное архитектурное решение — хранить развернутую иерархию в служебном непериодическом регистре сведений:

  1. Создаем регистр сведений со структурой: измерения Элемент (СправочникСсылка), Родитель (СправочникСсылка), Уровень (Число).
  2. В подписке на событие ПриЗаписи справочника заполняем регистр всеми вышестоящими родителями записываемого объекта.
  3. В целевом запросе соединяем таблицу настроек с регистром сведений по простому равенству втНастройки.ГруппаНоменклатуры = РегистрИерархии.Родитель, получая сразу все подчиненные элементы без использования условий по цепочкам точек.

Выбор конкретного способа зависит от возможности модификации метаданных конфигурации, предельной глубины иерархии и требований к быстродействию системы.

← На главную