Как в СКД получить самого верхнего родителя (корень) иерархии?

Программист
← На главную

При работе с иерархическими справочниками в 1С (такими как «Подразделения», «Номенклатура» или «Статьи затрат») часто возникает задача получить не просто непосредственного родителя элемента, а самый верхний узел в дереве — так называемый «корень». Использование конструкции типа Ссылка.Родитель.Родитель.Родитель является плохой практикой, так как она жестко ограничивает глубину вложенности и делает код громоздким. Разберем несколько эффективных способов решения этой задачи в системе компоновки данных (СКД).

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

Это самый «родной» для СКД метод, который позволяет динамически обходить дерево иерархии. Вместо того чтобы пытаться вычислить родителя в одном запросе, мы можем настроить рекурсивную связь между двумя наборами данных или одним набором, связанным с самим собой.

Рассмотрим по шагам, как это реализовать:

  1. Создадим основной набор данных (запрос), который выбирает необходимые нам элементы справочника.
  2. Перейдем на закладку «Связи наборов данных».
  3. В качестве источника связи укажем наш набор, в качестве приемника — его же (или второй набор по этому же справочнику).
  4. Укажем условие связи: Родитель (Источник) = Ссылка (Приемник).
  5. Для получения именно корня иерархии в СКД можно использовать настройки иерархических группировок. Если нам нужно вывести в одной строке и элемент, и его корень, мы можем создать вычисляемое поле, которое будет обращаться к верхнему уровню связи.

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

Способ 2. Определение корня через левое соединение в запросе

Если задача стоит в том, чтобы выбрать только те элементы, которые сами являются «самыми верхними» (не имеют родителей), или найти конечные узлы (листья), не имеющие детей, можно воспользоваться классическим приемом с левым соединением таблицы самой с собой.

Проанализируем пример кода для поиска «листьев» (элементов, которые не являются родителями ни для кого другого):


ВЫБРАТЬ
    Подразделения.Ссылка КАК Ссылка
ИЗ
    Справочник.Подразделения КАК Подразделения
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Подразделения КАК ПодразделенияПотомки
    ПО Подразделения.Ссылка = ПодразделенияПотомки.Родитель
ГДЕ
    ПодразделенияПотомки.Ссылка ЕСТЬ NULL
    И Подразделения.ЭтоГруппа = ЛОЖЬ

Для поиска корневых элементов логика обратная и более простая: мы просто ищем записи, у которых поле Родитель равно ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка). Однако, если нам нужно для каждого вложенного элемента «4» получить его корень «1», запрос становится сложнее.

Способ 3. Использование функции «ВычислитьВыражение» в СКД

Система компоновки данных предоставляет мощный механизм функций для работы с группировками. Функция ВычислитьВыражение с параметром «Иерархия» позволяет «дотянуться» до данных любого уровня вложенности.

Посмотрим на пример выражения для вычисляемого поля:

ВычислитьВыражение("Наименование", , "Иерархия", "Первая", "Первая")

Разберем, что здесь происходит:

Этот метод крайне эффективен, так как он не требует сложных соединений в запросе и работает на уровне постобработки данных компоновщиком.

Способ 4. Метод «взлета» по иерархии через временные таблицы

В ситуациях, когда иерархия очень глубокая, а данные нужно подготовить до передачи в СКД (например, в объектном наборе данных), можно использовать алгоритм последовательного приближения в коде 1С.

Проанализируем алгоритм:

  1. Выгружаем пары Ссылка / Родитель во временную таблицу.
  2. В цикле выполняем запрос, который обновляет поле Родитель, заменяя его на «родителя родителя».
  3. Цикл продолжается до тех пор, пока количество измененных строк больше нуля (ГДЕ Родитель.Родитель <> ЗНАЧЕНИЕ(...)).

Пример логики обновления во временной таблице:


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

В результате работы такого цикла в колонке ТекущийРодитель для каждой строки будет записан элемент самого верхнего уровня.

Способ 5. Использование виртуального поля «Полный код»

Выясним еще один «хитрый» способ. Если в справочнике настроено формирование кодов с учетом иерархии, то ПолныйКод() элемента содержит в себе коды всех его родителей, разделенные слешем (например, "001/005/012").

Хотя в языке запросов строковые функции ограничены, при программной подготовке данных мы можем:

  1. Получить ПолныйКод() элемента.
  2. Выделить первую часть строки до первого разделителя «/».
  3. Найти элемент по этому коду (при условии уникальности кодов в пределах уровня).

Резюмируем: Для большинства отчетов на СКД оптимальным будет Способ 3 (ВычислитьВыражение), так как он требует минимум кода и настроек. Если же нужно жестко отфильтровать данные еще на этапе запроса, используйте Способ 2 с анализом пустых ссылок родителей.

← На главную