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