Как в запросе 1С добавить поле с делением на значение из общих итогов

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет
← На главную

При разработке отчетов в системе 1С:Предприятие часто возникает задача рассчитать долю конкретной строки (например, продажи номенклатуры) в общем объеме продаж. Начинающие разработчики часто пытаются использовать для этого стандартную секцию ИТОГИ, однако язык запросов 1С имеет существенное ограничение: значения, рассчитанные в блоке ИТОГИ, недоступны для математических операций в блоке ВЫБРАТЬ того же самого запроса. Секция ИТОГИ служит лишь для формирования иерархической структуры выборки, которую потом обходит программный код.

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

Метод 1: Использование временных таблиц (ВТ)

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

Шаг 1. Сбор детальных данных во временную таблицу.

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


ВЫБРАТЬ
    Sales.Номенклатура КАК Номенклатура,
    Sales.Сумма КАК СуммаДетально
ПОМЕСТИТЬ ВТ_ДетальныеДанные
ИЗ
    (Ваш_Исходный_Подзапрос) КАК Sales
;

Шаг 2. Расчет общего итога.

Теперь создадим вторую временную таблицу, в которой будет всего одна строка, содержащая общую сумму по всем записям. Обратите внимание, что здесь мы не используем группировку по аналитике (номенклатуре или контрагенту), так как нам нужно одно число на весь отчет.


ВЫБРАТЬ
    СУММА(СуммаДетально) КАК СуммаОбщая
ПОМЕСТИТЬ ВТ_ОбщийИтог
ИЗ
    ВТ_ДетальныеДанные
;

Шаг 3. Соединение данных и расчет процента.

На финальном этапе мы выполняем левое соединение (или полное соединение) основной таблицы с таблицей итогов. Поскольку в таблице итогов всего одна строка, мы можем использовать условие ПО ИСТИНА. Рассмотрим, как это выглядит в итоговом запросе:


ВЫБРАТЬ
    Данные.Номенклатура,
    Данные.СуммаДетально,
    Итог.СуммаОбщая,
    ВЫБОР
        КОГДА ЕСТЬNULL(Итог.СуммаОбщая, 0) = 0
            ТОГДА 0
        ИНАЧЕ ВЫРАЗИТЬ(Данные.СуммаДетально * 100 / Итог.СуммаОбщая КАК ЧИСЛО(15, 2))
    КОНЕЦ КАК ПроцентОтОбщихПродаж
ИЗ
    ВТ_ДетальныеДанные КАК Данные
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ОбщийИтог КАК Итог
        ПО (ИСТИНА)

Важный момент: использование проверки на ноль в знаменателе является обязательным. Если за выбранный период не было продаж, СуммаОбщая будет равна 0, что приведет к аварийному завершению запроса при попытке деления.

Метод 2: Система компоновки данных (СКД)

Если вы не ограничены использованием старого объекта ПостроительОтчета, настоятельно рекомендуем перевести отчет на СКД. В СКД задача расчета процента от итога решается на уровне настроек ресурсов, что избавляет от необходимости усложнять текст запроса временными таблицами.

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

1. Откройте вкладку Ресурсы в схеме компоновки данных.

2. Добавьте новое поле или используйте существующее.

3. В колонке Выражение напишите формулу:

Сумма(Сумма) * 100 / ВычислитьВыражение("Сумма(Сумма)", "ОбщийИтог")

Функция ВычислитьВыражение позволяет обратиться к контексту итогов всего отчета (параметр "ОбщийИтог"), находясь при этом в строке конкретной группировки. Это самый современный и производительный метод в 1С 8.3.

Метод 3: Программная постобработка

В некоторых случаях, особенно при использовании ПостроительОтчета или ТабличныйДокумент, бывает проще рассчитать процент уже после выполнения запроса. Проанализируем этот подход:

  1. Выполняем запрос без вычисления процента.
  2. Выгружаем результат в ТаблицаЗначений через метод РезультатЗапроса.Выгрузить().
  3. Используем метод таблицы Итог("Сумма"), чтобы получить общее значение.
  4. Добавляем в таблицу новую колонку Процент.
  5. В цикле обходим строки таблицы и заполняем новую колонку результатом деления Строка.Сумма / ОбщийИтог * 100.

Этот способ удобен тем, что он не нагружает СУБД сложными соединениями, но требует написания дополнительного кода на языке 1С.

Типичные ошибки при реализации

Разберем ситуацию, с которой столкнулся автор темы. В его исходном коде используется сложная группировка по результатам функций ВЫРАЗИТЬ и ВЫБОР. Проанализируем, почему это может мешать расчету итогов:

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

Проблема точности: При делении больших чисел в запросе важно использовать функцию ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)). Без явного указания точности 1С может вернуть результат с неожиданным количеством знаков после запятой или округлить его до целого в зависимости от типов исходных данных.

Заключение

Мы рассмотрели три основных способа добавления поля с делением на общие итоги. Подведем итог:

Выбор метода зависит от архитектуры вашего отчета, но для новых разработок стандартом является использование механизмов СКД.

← На главную