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

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

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

Способ 1: Использование конструкции ВЫБОР КОГДА в запросе

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

Для реализации этого метода в тексте запроса набора данных создадим вычисляемое поле. Посмотрим на пример кода:


ВЫБОР
    КОГДА СправочникНоменклатура.Родитель ЕСТЬ NULL ТОГДА СправочникНоменклатура.Ссылка
    КОГДА СправочникНоменклатура.Родитель.Родитель ЕСТЬ NULL ТОГДА СправочникНоменклатура.Родитель
    КОГДА СправочникНоменклатура.Родитель.Родитель.Родитель ЕСТЬ NULL ТОГДА СправочникНоменклатура.Родитель.Родитель
    ИНАЧЕ СправочникНоменклатура.Родитель.Родитель.Родитель
КОНЕЦ КАК КорневойРодитель

Выясним причину, по которой этот метод популярен: он максимально прост в реализации и не требует написания программного кода. Однако у него есть существенный недостаток — ограничение по количеству уровней. Если в справочнике появится пятый уровень, отчет начнет выводить некорректные данные для глубоко вложенных элементов.

Способ 2: Использование связей наборов данных (Self-join)

Если мы хотим создать универсальное решение, которое будет работать при любой глубине иерархии, нам следует воспользоваться механизмом связей наборов данных в СКД. Этот метод позволяет рекурсивно сопоставить элемент с его корнем.

Разберем этот процесс по шагам:

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

Таким образом, СКД для каждой строки первого набора данных найдет соответствующий элемент во втором наборе, который является для него родителем самого верхнего уровня. Это мощный инструмент, который работает на уровне платформенных механизмов компоновки.

Способ 3: Программная обработка в модуле отчета

Иногда логика определения «корня» может быть сложнее, чем просто поиск пустого родителя (например, нужно игнорировать определенные служебные папки). В таких случаях мы можем использовать событие ПриКомпоновкеРезультате в модуле объекта отчета.

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

Сначала создадим в общем модуле (с флагами «Сервер», «Вызов сервера») функцию:


Функция ПолучитьСамогоВерхнегоРодителя(СсылкаНаЭлемент) Экспорт
    
    ТекущийРодитель = СсылкаНаЭлемент;
    
    Пока ЗначениеЗаполнено(ТекущийРодитель.Родитель) Цикл
        ТекущийРодитель = ТекущийРодитель.Родитель;
    КонецЦикла;
    
    Возврат ТекущийРодитель;
    
КонецФункции

Затем в СКД на закладке Вычисляемые поля добавим новое поле СамыйВерхнийРодитель и в выражении укажем:

ИмяВашегоОбщегоМодуля.ПолучитьСамогоВерхнегоРодителя(Ссылка)

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

Способ 4: Рекурсивные запросы (CTE) для версии 8.3.20 и выше

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Родитель КАК Родитель
ПОМЕСТИТЬ ИсходныеДанные
ИЗ
    Справочник.Номенклатура КАК Номенклатура;

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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Т.Ссылка,
    Иер.ТекущийРодитель
ИЗ
    ИсходныеДанные КАК Т
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Иерархия КАК Иер
        ПО Т.Родитель = Иер.ИсходнаяСсылка;

Этот метод является наиболее производительным с точки зрения работы СУБД, так как позволяет избежать многократных обращений к базе данных и использования тяжелых функций 1С внутри цикла компоновки.

Способ 5: Функция «ВычислитьВыражение» в СКД

Посмотрим на возможности языка выражений СКД. Функция ВычислитьВыражение позволяет обращаться к группировкам. Если ваш отчет уже сгруппирован по иерархии, вы можете получить значение верхней группировки.

Например, в поле выражения можно использовать конструкцию:

ВычислитьВыражение("Ссылка", "ИмяГруппировкиВерхнегоУровня", "ОбщийИтог")

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

Рекомендации по выбору метода

Выясним, какой метод лучше использовать в различных ситуациях:

При использовании любого из методов не забывайте обрабатывать предопределенные элементы. В некоторых конфигурациях корень может быть не пустой ссылкой, а конкретным предопределенным элементом (например, "Основная папка"), что потребует дополнительного условия в коде или запросе.

← На главную