К статье
Практический материал

Разработка и Конфигурация · 9 мин

Как посчитать сумму в запросе 1С

Как посчитать сумму в запросе 1С: функция СУММА, группировки, итоги по периодам и измерениям, типичные ошибки и проверка результата на примерах кода.

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

Ошибки в таких запросах приводят к типичным проблемам: сумма «задваивается» из-за лишних соединений, итог отличается от данных отчёта, а при пустом результате вместо нуля возвращается NULL. Ниже разобраны рабочие варианты подсчёта суммы, условия их применения и способы проверки корректности.

Базовый синтаксис функции СУММА

Агрегатная функция СУММА() складывает значения числового поля по всем строкам выборки или внутри каждой группы. Простейший пример — общая сумма всех реализаций:

ВЫБРАТЬ

СУММА(РеализацияТоваровУслуг.СуммаДокумента) КАК СуммаИтого

ИЗ

Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

ГДЕ

РеализацияТоваровУслуг.Проведен

Такой запрос вернёт одну строку с одним полем. Если выборка пустая (например, ни одного проведённого документа), функция вернёт NULL, а не ноль — это важно учитывать при дальнейшей обработке результата в коде, так как сравнение и арифметика с NULL дают NULL.

Чтобы гарантированно получить число, оберните агрегат в ЕСТЬNULL:

ВЫБРАТЬ

ЕСТЬNULL(СУММА(Таб.Сумма), 0) КАК СуммаИтого

ИЗ

Документ.РеализацияТоваровУслуг КАК Таб

Сумма по группам: СГРУППИРОВАТЬ ПО

Чаще всего нужна не общая сумма, а суммы в разрезе контрагентов, складов, номенклатуры или периодов. Для этого неагрегатные поля выборки перечисляются в секции СГРУППИРОВАТЬ ПО:

ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

СУММА(Продажи.СуммаОборот) КАК СуммаПродаж

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Контрагент

УПОРЯДОЧИТЬ ПО

СуммаПродаж УБЫВ

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

Группировать можно и по выражениям, например по месяцу документа: СГРУППИРОВАТЬ ПО МЕСЯЦ(Таб.Дата). Но если поле месяца выводится в выборку, его тоже нужно указать в группировке в том же виде.

Порядок действий
  1. 1
    Определите, какие суммы нужны: общий итог или суммы по группам
  2. 2
    Напишите запрос с СУММА(Поле) и при необходимости СГРУППИРОВАТЬ ПО
  3. 3
    Добавьте ЕСТЬNULL вокруг агрегата, если возможна пустая выборка
  4. 4
    Выполните запрос в консоли запросов на тестовой базе
  5. 5
    Сверьте итог с типовым отчётом по тому же регистру за тот же период

Многоуровневые итоги через ИТОГИ ПО

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

ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

Продажи.Номенклатура КАК Номенклатура,

СУММА(Продажи.СуммаОборот) КАК Сумма

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Контрагент,

Продажи.Номенклатура

ИТОГИ

СУММА(Сумма)

ПО

Контрагент

Если нужен общий итог по всей выборке, используется ИТОГИ СУММА(Сумма) ПО ОБЩИЕ. Комбинация ПО ОБЩИЕ, Контрагент даст и общий итог, и итоги по каждому контрагенту в одном результате.

Сравнение вариантов

СГРУППИРОВАТЬ ПО

Возвращает только строки итогов. Подходит для плоских таблиц, сводных данных и последующих соединений.

ИТОГИ ПО

Сохраняет детальные строки и добавляет итоговые. Подходит для древовидных отчётов, но требует обхода по группировкам в коде.

Виртуальная таблица Обороты/Остатки

Платформа сама агрегирует данные регистра — часто это быстрее, чем суммировать физические записи вручную.

Сумма по виртуальным таблицам регистров

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

ВЫБРАТЬ

Остатки.Склад КАК Склад,

СУММА(Остатки.КоличествоОстаток) КАК Количество,

СУММА(Остатки.СуммаОстаток) КАК Сумма

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, ) КАК Остатки

СГРУППИРОВАТЬ ПО

Остатки.Склад

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

Если виртуальная таблица Обороты уже возвращает данные в нужном разрезе, дополнительная группировка с СУММА не требуется — достаточно выбрать поля как есть. Лишняя группировка не исказит данные, но усложнит запрос и план его выполнения.
ПЗ
Практическое замечание

Условные суммы и фильтрация

Когда нужно посчитать сумму только по части строк (например, отдельно оплаченные и неоплаченные счета), есть два подхода. Первый — общий фильтр в секции ГДЕ, если условие одно для всего запроса. Второй — условие внутри агрегата через ВЫБОР КОГДА, если разных сумм несколько:

ВЫБРАТЬ

СУММА(ВЫБОР

КОГДА Таб.Оплачен

ТОГДА Таб.Сумма

ИНАЧЕ 0

КОНЕЦ) КАК СуммаОплачено,

СУММА(ВЫБОР

КОГДА НЕ Таб.Оплачен

ТОГДА Таб.Сумма

ИНАЧЕ 0

КОНЕЦ) КАК СуммаНеОплачено

ИЗ

Документ.СчетНаОплатуПокупателю КАК Таб

Фильтрацию групп (не строк) выполняет секция ИМЕЮЩИЕ — например, выбрать только контрагентов с суммой продаж больше заданной: ИМЕЮЩИЕ СУММА(Продажи.СуммаОборот) > &МинСумма. Помещать такое условие в ГДЕ нельзя: ГДЕ отрабатывает до агрегации, ИМЕЮЩИЕ — после.

Проверка результата и типичные ошибки

Самый надёжный способ проверки — сверка с типовым отчётом. Если вы суммируете обороты регистра «Продажи», откройте универсальный отчёт или типовой отчёт по этому регистру за тот же период с теми же отборами и сравните итог. Расхождение означает разницу в отборах, периоде или составе измерений.

При отладке полезно временно убрать группировку и посмотреть детальные строки: так видно, какие записи попадают в сумму и нет ли среди них лишних. Консоль запросов (в типовых конфигурациях — встроенная или внешняя обработка) позволяет выполнять запрос интерактивно с параметрами.

Типичные ошибки
01
Соединение с табличной частью документа без группировки: сумма документа умножается на количество строк товаров
02
Сравнение результата с NULL: при пустой выборке СУММА возвращает NULL, и условие Сумма = 0 не сработает — используйте ЕСТЬNULL
03
Отбор в ГДЕ вместо ИМЕЮЩИЕ для агрегата: запрос либо не выполнится, либо отфильтрует строки до суммирования
04
Суммирование физических движений регистра вместо виртуальной таблицы Обороты: медленно и легко ошибиться с видом движения
05
Забытое поле выборки в СГРУППИРОВАТЬ ПО: синтаксическая ошибка или неожиданная детализация результата
Контрольные точки

Как проверить результат

Общий итог запроса
Норма

Совпадает с типовым отчётом по регистру за тот же период и с теми же отборами

Тревожный признак

Итог больше или меньше — ищите разницу в отборах и соединениях

Сумма по группам
Норма

Сумма по всем группам равна общему итогу без группировки

Тревожный признак

Часть данных потерялась — вероятно, внутреннее соединение отсекло строки

Пустая выборка
Норма

Возвращается 0 благодаря ЕСТЬNULL

Тревожный признак

Возвращается NULL, что ломает дальнейшие вычисления в коде

Частые вопросы

Чем СУММА отличается от ИТОГИ ПО?

СУММА — агрегатная функция, сворачивающая строки в группы. ИТОГИ ПО — конструкция, которая оставляет детальные строки и добавляет к ним итоговые записи по указанным полям. Для плоской сводной таблицы достаточно СУММА с группировкой; для иерархических отчётов удобнее ИТОГИ ПО с обходом по группировкам.

Почему запрос возвращает NULL вместо суммы?

Агрегатные функции возвращают NULL, когда в выборке нет ни одной строки или все значения поля равны NULL. Оберните выражение в ЕСТЬNULL(СУММА(Поле), 0), чтобы гарантированно получить число.

Как посчитать сумму только за выбранный период?

Передайте даты в параметры виртуальной таблицы Обороты или добавьте условие в ГДЕ: Таб.Дата МЕЖДУ &НачалоПериода И &КонецПериода. Для виртуальных таблиц предпочтительнее первый способ — он эффективнее по производительности.

Можно ли суммировать поле с составным типом?

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

Как посчитать сумму в СКД, а не в тексте запроса?

В схеме компоновки данных поле суммы добавляется на закладке «Ресурсы» с выражением Сумма(Поле). СКД сама сформирует группировки и итоги по настройкам отчёта, вручную писать СГРУППИРОВАТЬ ПО в запросе набора данных обычно не требуется.

Почему сумма в запросе не совпадает с отчётом?

Чаще всего причины: разные отборы (например, отчёт исключает непроведённые документы), разные границы периода (дата против границы с включением секунды), лишние соединения в запросе или использование разных источников — физической таблицы вместо виртуальной. Сверяйте параметры по одному, начиная с периода.

Итог

Что важно запомнить

Сумма в запросе 1С считается через СУММА() с группировкой СГРУППИРОВАТЬ ПО или через ИТОГИ ПО для иерархии. Для регистров используйте виртуальные таблицы Обороты и Остатки, оборачивайте агрегат в ЕСТЬNULL и проверяйте итог сверкой с типовым отчётом.