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