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