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