При работе с иерархическими справочниками в 1С (такими как «Подразделения», «Номенклатура» или «Статьи затрат») часто возникает задача получить не просто непосредственного родителя элемента, а самый верхний узел в дереве — так называемый «корень». Использование конструкции типа Ссылка.Родитель.Родитель.Родитель является плохой практикой, так как она жестко ограничивает глубину вложенности и делает код громоздким. Разберем несколько эффективных способов решения этой задачи в системе компоновки данных (СКД).
Это самый «родной» для СКД метод, который позволяет динамически обходить дерево иерархии. Вместо того чтобы пытаться вычислить родителя в одном запросе, мы можем настроить рекурсивную связь между двумя наборами данных или одним набором, связанным с самим собой.
Рассмотрим по шагам, как это реализовать:
Родитель (Источник) = Ссылка (Приемник).Важный нюанс: Чтобы СКД понимала, где заканчивается дерево, в параметрах связи можно указать начальное условие (например, Родитель равен пустой ссылке для поиска сверху вниз или наоборот).
Если задача стоит в том, чтобы выбрать только те элементы, которые сами являются «самыми верхними» (не имеют родителей), или найти конечные узлы (листья), не имеющие детей, можно воспользоваться классическим приемом с левым соединением таблицы самой с собой.
Проанализируем пример кода для поиска «листьев» (элементов, которые не являются родителями ни для кого другого):
ВЫБРАТЬ
Подразделения.Ссылка КАК Ссылка
ИЗ
Справочник.Подразделения КАК Подразделения
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК ПодразделенияПотомки
ПО Подразделения.Ссылка = ПодразделенияПотомки.Родитель
ГДЕ
ПодразделенияПотомки.Ссылка ЕСТЬ NULL
И Подразделения.ЭтоГруппа = ЛОЖЬ
Для поиска корневых элементов логика обратная и более простая: мы просто ищем записи, у которых поле Родитель равно ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка). Однако, если нам нужно для каждого вложенного элемента «4» получить его корень «1», запрос становится сложнее.
Система компоновки данных предоставляет мощный механизм функций для работы с группировками. Функция ВычислитьВыражение с параметром «Иерархия» позволяет «дотянуться» до данных любого уровня вложенности.
Посмотрим на пример выражения для вычисляемого поля:
ВычислитьВыражение("Наименование", , "Иерархия", "Первая", "Первая")
Разберем, что здесь происходит:
Этот метод крайне эффективен, так как он не требует сложных соединений в запросе и работает на уровне постобработки данных компоновщиком.
В ситуациях, когда иерархия очень глубокая, а данные нужно подготовить до передачи в СКД (например, в объектном наборе данных), можно использовать алгоритм последовательного приближения в коде 1С.
Проанализируем алгоритм:
Ссылка / Родитель во временную таблицу.Родитель, заменяя его на «родителя родителя».ГДЕ Родитель.Родитель <> ЗНАЧЕНИЕ(...)).Пример логики обновления во временной таблице:
ВЫБРАТЬ
ТЗ.Ссылка,
ЕСТЬNULL(Спр.Родитель, ТЗ.ТекущийРодитель) КАК НовыйРодитель
ИЗ
ВременнаяТаблицаДанных КАК ТЗ
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК Спр
ПО ТЗ.ТекущийРодитель = Спр.Ссылка
В результате работы такого цикла в колонке ТекущийРодитель для каждой строки будет записан элемент самого верхнего уровня.
Выясним еще один «хитрый» способ. Если в справочнике настроено формирование кодов с учетом иерархии, то ПолныйКод() элемента содержит в себе коды всех его родителей, разделенные слешем (например, "001/005/012").
Хотя в языке запросов строковые функции ограничены, при программной подготовке данных мы можем:
ПолныйКод() элемента.Резюмируем: Для большинства отчетов на СКД оптимальным будет Способ 3 (ВычислитьВыражение), так как он требует минимум кода и настроек. Если же нужно жестко отфильтровать данные еще на этапе запроса, используйте Способ 2 с анализом пустых ссылок родителей.