При разработке отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются со специфическим поведением платформы при выводе иерархии — ускоряет работу инструментарий для разработки и отладки с консолью СКД. Проблема проявляется в справочниках с типом "Иерархия элементов" (где нет разделения на группы и элементы, и каждый объект может быть родителем). В этом случае один и тот же элемент выводится дважды: сначала как узел иерархии (родитель), а затем как детальная запись. Попытки просто отсечь лишние записи через запрос часто приводят к тому, что стандартные отборы СКД перестают работать корректно: либо исчезают нужные данные, либо иерархическое дерево "рассыпается".
В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим наиболее надежные способы её решения, которые позволяют сохранить иерархическую структуру и полную работоспособность отборов. В качестве готового примера построения дерева элементов можно использовать отчет с реализацией произвольной иерархии в СКД.
Для начала проанализируем ситуацию. Когда мы включаем в настройках СКД группировку Иерархия, платформа 1С выполняет дополнительные итерации для построения дерева. В справочниках с иерархией элементов запись является одновременно и "контейнером" для подчиненных элементов, и самостоятельной единицей данных. СКД генерирует строку для иерархического уровня и отдельную строку для детальных записей этого же уровня. Если у элемента есть подчиненные, он отобразится как ветка дерева. Если мы хотим видеть его собственные данные (реквизиты, ресурсы), он отобразится еще раз внутри этой ветки.
Стандартное условие в запросе типа ГДЕ НЕ ЭтоГруппа здесь не поможет, так как реквизита ЭтоГруппа просто не существует в данной структуре. А условие ГДЕ Тест.Родитель <> ЗНАЧЕНИЕ(...) отсечет только элементы верхнего уровня, но не решит проблему дублей внутри дерева.
Это наиболее элегантное и стабильное решение, которое рекомендуют специалисты фирмы 1С. Оно основано на использовании функций языка выражений СКД для определения контекста вывода записи.
Шаг 1: Создание вспомогательного поля
Нам необходимо создать поле, которое будет хранить ссылку на родителя в контексте текущей иерархии. Перейдем на закладку "Вычисляемые поля" (или создадим "Пользовательское поле" непосредственно в настройках отчета) и добавим поле, например, с заголовком РодительИерархии.
В выражении этого поля пропишем следующую функцию:
ВычислитьВыражение("ИмяВашегоПоляСсылка", "", "Иерархия")
Важно: укажите аналогичное выражение и в поле итогов для этого вычисляемого поля.
Шаг 2: Настройка условий в группировке
Теперь перейдем в настройки отчета на закладку "Настройки". Выберем нашу иерархическую группировку и перейдем на её вкладку "Отбор". Нам нужно добавить группу условий с типом ИЛИ. В эту группу добавим два условия:
ИмяВашегоПоляСсылка Не равно полю РодительИерархии.УровеньВГруппировке Равно 1.Важный нюанс: для этих условий в колонке "Применение" необходимо выбрать значение "После группировки или для иерархии". Это критически важно, так как обычный отбор отсечет данные еще на этапе выборки из базы, а нам нужно, чтобы СКД сначала построила дерево, а потом "схлопнула" дублирующиеся строки.
Рассмотрим ситуацию, когда нам нужно быстро избавиться от дублей на уровне источника данных. Как отмечалось в обсуждении, можно использовать условие исключения тех записей, которые сами являются родителями для других элементов.
Проанализируем пример кода для текста запроса:
ВЫБРАТЬ
Тест.Ссылка КАК Ссылка,
Тест.Наименование КАК Наименование
ИЗ
Справочник.Тест КАК Тест
ГДЕ
НЕ Тест.Ссылка В (
ВЫБРАТЬ
Т.Родитель
ИЗ
Справочник.Тест КАК Т
ГДЕ
Т.Родитель <> ЗНАЧЕНИЕ(Справочник.Тест.ПустаяСсылка)
)
Однако будьте внимательны: этот метод имеет существенный недостаток. Если элемент является родителем, он полностью пропадет из детальных записей, и вы не сможете увидеть его собственные числовые показатели (ресурсы) или специфические реквизиты. Этот способ подходит только для простых списков без суммируемых итогов.
Выясним причину, по которой иногда помогает простое перестроение группировок. Если иерархия элементов выводится в "плоском" виде, попробуйте изменить структуру настроек.
Рассмотрим алгоритм действий:
Ссылка с типом "Иерархия".Это позволит визуально отделить "узел" дерева от его "содержимого". Чтобы убрать пустые строки у узлов, примените отбор на уровне группировки Детальные записи: СистемныеПоля.УровеньВГруппировке > 0.
Проанализируем ситуацию, когда при иерархии элементов у нас удваиваются суммы. Если один и тот же элемент выводится и как папка, и как строка, СКД может просуммировать его дважды в общих итогах. Чтобы этого избежать, мы рекомендуем использовать в ресурсах агрегатную функцию с уточнением по группировке. Для более сложных сценариев настройки итогов на разных уровнях иерархии можно использовать подход с разделением расчета ресурсов для различных группировок.
Вместо стандартного Сумма(Количество) используйте выражение:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(Количество)", "Ссылка"))
Это гарантирует, что для каждой уникальной ссылки значение будет взято только один раз, независимо от того, сколько раз эта ссылка встречается в иерархическом дереве отчета.
Мы рассмотрели несколько подходов к решению проблемы дублей. Подведем итог: метод с использованием функции ВычислитьВыражение и фильтрацией "После группировки" является наиболее универсальным. Он позволяет сохранить структуру дерева, не "ломает" пользовательские отборы по реквизитам и корректно обрабатывает данные элементов-родителей. При использовании этого метода пользователь может накладывать любые фильтры (например, по цене или остатку), и иерархия будет подстраиваться под них динамически, скрывая пустые ветки или показывая путь к найденному элементу.