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