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