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