Как правильно рассчитать проценты от итоговых значений в отчетах 1С, избегая суммирования процентов элементов?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При формировании отчетов в системе 1С разработчики часто сталкиваются с задачей корректного расчета процентов от итоговых значений. Распространенная ошибка заключается в том, что вместо вычисления процента на основе сумм исходных показателей, система пытается просуммировать уже рассчитанные процентные значения для каждой детализированной строки. Это приводит к некорректным результатам на уровне группировок и общих итогов. В этой статье мы подробно рассмотрим, как правильно подходить к решению этой задачи, используя как прямые запросы 1С, так и возможности Системы Компоновки Данных (СКД).

Понимание основной проблемы: суммирование процентов против процента от сумм

Чтобы глубже понять суть проблемы, давайте проанализируем типичную ситуацию. Предположим, у нас есть данные о "Получено" и "Продажи" по каждому "Региону". Наша цель — вычислить процент "Получено от Продаж". Если мы для каждой строки или детального элемента таблицы вычислим этот процент (например, Получено / Продажи * 100) и затем попытаемся просуммировать эти проценты на уровне группировки или общего итога, результат будет математически неверным. Сумма процентов от отдельных частей редко (или никогда) равна проценту от общей суммы этих частей.

Правильный подход заключается в том, чтобы сначала просуммировать исходные показатели ("Получено" и "Продажи") для нужного уровня агрегации (например, по региону, по группе товаров, по отчету в целом), а затем уже вычислить процент из этих агрегированных сумм. То есть, формула должна выглядеть как СУММА(Получено) / СУММА(Продажи) * 100, где функция СУММА() применяется к исходным данным в контексте текущей группировки.

Решение для прямого запроса 1С и ДереваЗначений

Предположим, вы строите отчет, используя прямой запрос к базе данных 1С, а результат запроса выгружаете в объект ДеревоЗначений для отображения на форме. Именно с такой ситуацией столкнулся автор вопроса.

Исходный запрос автора, представленный в сообщении 5, выглядел следующим образом:


ВЫБРАТЬ
    ВТ_Остатки.Регионы КАК Регионы,
    ВТ_Остатки.НачОстаток КАК НачОстаток,
    ВТ_Остатки.Продажи КАК Продажи,
    ВТ_Остатки.Получено КАК Получено,
    ВТ_Остатки.КонОстаток КАК КонОстаток,
    ВЫБОР КОГДА СУММА(ВТ_Остатки.Получено) > 0 ТОГДА СУММА(ВТ_Остатки.Получено) / СУММА(ВТ_Остатки.Продажи) * 100 КОНЕЦ КАК ВПроцентах
ИЗ
    ВТ_Остатки КАК ВТ_Остатки
СГРУППИРОВАТЬ ПО
    ВТ_Остатки.Регионы,
    ВТ_Остатки.НачОстаток,
    ВТ_Остатки.Продажи,
    ВТ_Остатки.Получено,
    ВТ_Остатки.КонОстаток
ИТОГИ
    СУММА(НачОстаток),
    СУММА(Продажи),
    СУММА(Получено),
    СУММА(КонОстаток),
    СУММА(ВПроцентах)
ПО Регионы ИЕРАРХИЯ

Здесь проблема находится в секции ИТОГИ, а именно в строке СУММА(ВПроцентах). В данном случае система пытается просуммировать значения, которые уже являются процентами, рассчитанными для каждого элемента группировки. Это приводит к завышенным и некорректным итоговым процентам.

Для исправления этой ошибки нам необходимо изменить формулу в секции ИТОГИ для поля ВПроцентах. Вместо суммирования процентов, мы должны указать, что для итогов процент также должен вычисляться из сумм исходных показателей "Получено" и "Продажи". Кроме того, крайне важно предусмотреть защиту от деления на ноль, если показатель "Продажи" может быть равен нулю.

Правильный вариант модифицированного запроса будет выглядеть так:


ВЫБРАТЬ
    ВТ_Остатки.Регионы КАК Регионы,
    ВТ_Остатки.НачОстаток КАК НачОстаток,
    ВТ_Остатки.Продажи КАК Продажи,
    ВТ_Остатки.Получено КАК Получено,
    ВТ_Остатки.КонОстаток КАК КонОстаток,
    ВЫБОР КОГДА СУММА(ВТ_Остатки.Продажи) = 0 ТОГДА 0 ИНАЧЕ СУММА(ВТ_Остатки.Получено) / СУММА(ВТ_Остатки.Продажи) * 100 КОНЕЦ КАК ВПроцентах
ИЗ
    ВТ_Остатки КАК ВТ_Остатки
СГРУППИРОВАТЬ ПО
    ВТ_Остатки.Регионы
ИТОГИ
    СУММА(НачОстаток),
    СУММА(Продажи),
    СУММА(Получено),
    СУММА(КонОстаток),
    ВЫБОР КОГДА СУММА(Продажи) = 0 ТОГДА 0 ИНАЧЕ СУММА(Получено) / СУММА(Продажи) * 100 КОНЕЦ
ПО Регионы ИЕРАРХИЯ

Давайте разберем ключевые изменения и их смысл:

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

После внесения этих изменений, поле "ВПроцентах" в дереве значений будет отображать правильные проценты как для детальных строк (если они получаются из запроса), так и для всех уровней группировки, включая общие итоги. Сообщение 10 в теме форума подтверждает, что именно это изменение решило проблему автора.

Решение для Системы Компоновки Данных (СКД)

Система Компоновки Данных (СКД) является мощным инструментом в 1С для построения отчетов и предоставляет более гибкие и удобные механизмы для работы с агрегированными данными и вычисляемыми полями. Если вы создаете отчет в СКД, то задача расчета процентов от итогов решается с помощью настройки ресурсов.

В СКД нам не нужно вручную прописывать секцию ИТОГИ в запросе. Вместо этого мы определяем вычисляемое поле (ресурс), которое будет автоматически агрегироваться по всем уровням группировки.

Мы рассмотрим следующие шаги:

  1. Определяем набор данных. В вашем запросе СКД вы выбираете необходимые поля, например, "Регионы", "Получено", "Продажи".
    
    ВЫБРАТЬ
        ВТ_Остатки.Регионы КАК Регионы,
        ВТ_Остатки.Продажи КАК Продажи,
        ВТ_Остатки.Получено КАК Получено
    ИЗ
        ВТ_Остатки КАК ВТ_Остатки
    
  2. Создаем вычисляемое поле (ресурс). Переходим на вкладку "Ресурсы" в СКД. Здесь мы добавляем новое поле, назовем его, например, "ПроцентПолучения". В качестве выражения для этого ресурса мы указываем формулу, которая будет работать с агрегированными данными:
    
    Сумма(Получено) / Сумма(Продажи) * 100
    
    Важно, что СКД автоматически подставит правильный контекст для функций Сумма(). Если вы смотрите на детальную строку, то Сумма(Получено) будет равно значению "Получено" этой строки. Если вы смотрите на итоги по группе, то Сумма(Получено) будет равно сумме "Получено" по всем строкам этой группы.
  3. Обработка деления на ноль. Как и в прямом запросе, необходимо предусмотреть ситуацию, когда "Продажи" могут быть равны нулю. В выражении ресурса мы используем конструкцию ВЫБОР КОГДА:
    
    ВЫБОР КОГДА Сумма(Продажи) = 0 ТОГДА 0 ИНАЧЕ Сумма(Получено) / Сумма(Продажи) * 100 КОНЕЦ
    
    Это выражение обеспечит корректное отображение нуля вместо ошибки при делении на ноль.
  4. Настройка группировок. На вкладке "Настройки" вы добавляете нужные группировки, например, "Регионы". СКД автоматически применит формулу ресурса для каждого уровня группировки и для общих итогов, вычисляя процент от агрегированных сумм.

Преимущество СКД в том, что однажды настроенное выражение ресурса автоматически применяется ко всем уровням иерархии отчета (детальные записи, группировки, общие итоги), всегда вычисляя процент из сумм исходных показателей, а не суммируя проценты.

Условный расчет процентов на разных уровнях группировки

В некоторых случаях может потребоваться различный расчет или отображение данных в зависимости от уровня группировки в отчете. Например, для детальных строк мы хотим показать один процент, а для итоговых строк — другой агрегированный показатель, или вовсе скрыть процент для определенных уровней. В СКД для таких задач мы можем использовать специальную функцию УровеньВГруппировке.

Функция УровеньВГруппировке возвращает числовой индекс текущего уровня группировки: 0 для общих итогов, 1 для первой (верхней) группировки, 2 для второй и так далее. Для детальных записей (если они отображаются) эта функция возвращает значение, на единицу большее максимального уровня группировки.

Рассмотрим пример, адаптированный из сообщения 9, где для детальных записей (предположим, что они соответствуют максимальному уровню группировки + 1) выводится один расчет, а для итоговых — другой. Пусть наш отчет имеет одну группировку по "Регионам", и мы хотим видеть процент получения для каждого региона, но для общих итогов (УровеньВГруппировке = 0) мы хотим вывести просто сумму "Получено".

Выражение ресурса может выглядеть следующим образом:


ВЫБОР
    КОГДА УровеньВГруппировке = 0 ТОГДА Сумма(Получено) // Для общих итогов выводим сумму Получено
    КОГДА Сумма(Продажи) = 0 ТОГДА 0 // Для других уровней, если Продажи = 0, то 0
    ИНАЧЕ Сумма(Получено) / Сумма(Продажи) * 100 // В остальных случаях (группировки, детальные записи) - процент
КОНЕЦ

В этом примере:

  1. Если текущий уровень является общими итогами (УровеньВГруппировке = 0), мы выводим просто Сумма(Получено).
  2. Для всех остальных уровней (группировки по "Регионам", детальные записи), мы сначала проверяем деление на ноль: если Сумма(Продажи) = 0, то выводим 0.
  3. В противном случае (для группировок или детальных записей, где Сумма(Продажи) не ноль), мы вычисляем корректный процент Сумма(Получено) / Сумма(Продажи) * 100.

Таким образом, функция УровеньВГруппировке дает нам мощный инструмент для тонкой настройки отображения и расчета показателей в зависимости от иерархической структуры отчета, делая отчеты более информативными и специализированными.

Ключевые принципы и рекомендации

Чтобы избежать ошибок при расчете процентов от итогов в 1С, мы рекомендуем придерживаться следующих ключевых принципов:

  1. Всегда вычисляйте проценты от сумм исходных показателей: Главное правило – сначала агрегируйте базовые значения (числитель и знаменатель) для соответствующего уровня группировки, а затем выполняйте деление. Избегайте суммирования уже рассчитанных процентных значений.
  2. Обеспечивайте защиту от деления на ноль: Включение проверки на ноль для знаменателя (например, ВЫБОР КОГДА Знаменатель = 0 ТОГДА 0 ИНАЧЕ Числитель / Знаменатель КОНЕЦ) является обязательным шагом для предотвращения ошибок в отчетах.
  3. Понимайте контекст агрегации: Будьте внимательны к тому, как функции СУММА() (в запросах) или ресурсы (в СКД) работают в контексте детальных записей, группировок и общих итогов. Для прямых запросов это означает, что формулу для итогов нужно явно прописывать в секции ИТОГИ. В СКД это происходит автоматически.
  4. Используйте СКД для сложных отчетов: Для большинства отчетов, особенно с несколькими уровнями группировки, СКД является предпочтительным инструментом. Она значительно упрощает настройку вычисляемых полей и агрегаций, автоматически применяя правильную логику для разных уровней.
  5. Рассматривайте условную логику для специфических требований: Если на разных уровнях отчета нужны разные расчеты или форматы отображения, используйте возможности СКД, такие как УровеньВГруппировке, для создания гибких выражений ресурсов.

Следуя этим рекомендациям, вы сможете создавать надежные и корректные отчеты в 1С, точно отображающие проценты от итоговых значений, что критически важно для анализа данных и принятия управленческих решений.

← На главную