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

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

Как сделать расчет суммы в 1С

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

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

Универсального «единственно правильного» способа нет. Для табличной части документа обычно достаточно встроенного метода Итог(), для данных регистров правильнее использовать агрегатную функцию СУММА() в запросе, а в отчетах на системе компоновки данных суммы считаются ресурсами. Ниже разобраны все основные сценарии с примерами кода и типичными ошибками.

Как посчитать сумму по табличной части документа

Самая простая задача — получить итог по колонке табличной части, например сумму всех строк документа «Реализация товаров и услуг». Для этого у табличной части есть встроенный метод Итог(), которому передается имя колонки.

СуммаДокумента = Объект.Товары.Итог("Сумма");

СуммаНДС = Объект.Товары.Итог("СуммаНДС");

Метод работает только с числовыми колонками и суммирует значения всех строк, загруженных в данные объекта. Если документ еще не записан, а строки добавляются динамически, итог пересчитывается при каждом вызове — это безопасно, но при большом числе строк и частых вызовах в цикле стоит кэшировать результат в переменную.

Если нужно пересчитать сумму строки при изменении количества или цены, в типовых конфигурациях это делается в обработчиках событий ПриИзменении полей табличной части. Простейший вариант выглядит так:

&НаКлиенте

Процедура ТоварыКоличествоПриИзменении(Элемент)

Строка = Элементы.Товары.ТекущиеДанные;

Строка.Сумма = Строка.Количество * Строка.Цена;

КонецПроцедуры

Как рассчитать сумму в запросе с помощью функции СУММА

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

ВЫБРАТЬ

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

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

ИЗ

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

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

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

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

Чтобы обезопасить себя от NULL, применяйте функцию ЕСТЬNULL() либо в запросе, либо при обработке результата:

СУММА(ЕСТЬNULL(Продажи.СуммаОборот, 0)) КАК СуммаПродаж
bsl
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ СУММА(Обороты.СуммаОборот) КАК Итог ИЗ РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК Обороты";
Запрос.УстановитьПараметр("Начало", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("Конец", КонецМесяца(ТекущаяДата()));
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    Итог = Выборка.Итог;
КонецЕсли;

Как посчитать сумму обходом выборки в коде

Иногда сумму нужно считать вручную: например, когда к строкам применяются сложные условия, которые неудобно выразить в запросе, или когда расчет идет по данным, полученным из нескольких источников. В этом случае используется цикл по выборке или коллекции с накоплением результата.

ИтоговаяСумма = 0;

Пока Выборка.Следующий() Цикл

Если Выборка.СтавкаНДС = Перечисления.СтавкиНДС.НДС20 Тогда

ИтоговаяСумма = ИтоговаяСумма + Выборка.Сумма;

КонецЕсли;

КонецЦикла;

Такой подход оправдан только тогда, когда запросом воспользоваться нельзя или объем данных заведомо мал. Обход большой выборки в коде медленнее агрегации на сервере СУБД и создает лишнюю нагрузку, особенно в клиент-серверном режиме, где выборка передается по сети.

Сравнение способов расчета суммы

Метод Итог() табличной части

Подходит для одного документа в памяти. Ограничение: работает только с загруженной табличной частью, не для данных базы.

СУММА() в запросе

Оптимально для регистров и больших объемов. Ограничение: требует корректной группировки и обработки NULL.

Цикл с накоплением в коде

Гибкий, подходит для сложных условий. Ограничение: медленнее запроса, нежелателен для больших выборок.

Ресурсы СКД

Для отчетов без программирования. Ограничение: применимо только внутри схемы компоновки данных.

Как настроить расчет суммы в отчете на СКД

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

Если сумма в отчете не выводится или равна нулю, чаще всего причина в том, что поле не добавлено в ресурсы, либо для ресурса не указано выражение, либо поле не включено в выбранные поля настройки отчета. Проверяйте также «Рассчитывать по» у ресурса: если задано ограничение по группировкам, итоги на других уровнях будут пустыми.

Для вычисляемых показателей, например суммы с НДС, используйте вкладку «Вычисляемые поля»: там задается выражение вида Сумма + СуммаНДС, после чего это поле тоже можно сделать ресурсом и суммировать.

Настройка суммы в отчете СКД
  1. 1
    Сформируйте запрос набора данных с нужным числовым полем
  2. 2
    На вкладке «Ресурсы» добавьте поле и выберите функцию Сумма
  3. 3
    Убедитесь, что поле добавлено в выбранные поля настройки отчета
  4. 4
    Сформируйте отчет и сверьте итог с контрольным значением из стандартного отчета

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

Для регистров накопления и бухгалтерии есть альтернатива запросу — методы получения итогов из встроенного языка. Например, у регистра бухгалтерии можно получить сальдо по счету через запрос к виртуальной таблице остатков, а у регистров накопления итоги по периодам доступны через виртуальные таблицы Обороты и Остатки.

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

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

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

Контрольные точки

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

Итог по табличной части
Норма

Совпадает с итоговой суммой в форме документа

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

Расхождение — проверьте имя колонки в Итог() и отборы строк

СУММА() в запросе
Норма

Результат числовой, совпадает со стандартным отчетом за период

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

NULL вместо суммы или завышенный итог из-за дублирования строк соединением

Сумма в отчете СКД
Норма

Итоги по группировкам сходятся с общим итогом

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

Пустые итоги — поле не добавлено в ресурсы или не выбрано в настройках

Типичные ошибки
01
Суммирование без обработки NULL — итог превращается в NULL или падает сложение в коде; исправляется через ЕСТЬNULL
02
Соединение таблиц без группировки дублирует строки, и СУММА() завышается в разы; проверяйте кратность соединения
03
Опечатка в имени колонки метода Итог() — ошибка выполнения; имя должно точно совпадать с реквизитом табличной части
04
Расчет суммы по физической таблице регистра вместо виртуальной — резкое падение производительности
05
Игнорирование отмененных или непроведенных документов — итоги не сходятся с бухгалтерией; добавляйте отбор по проведенным

Часто задаваемые вопросы

Почему СУММА() в запросе возвращает NULL вместо числа?

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

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

Метод Итог() не поддерживает отборы, поэтому нужно пройти циклом по коллекции строк и сложить значения строк, удовлетворяющих условию, либо использовать метод НайтиСтроки() с параметрами отбора и просуммировать результат.

Чем отличается Итог() табличной части от итога в запросе?

Итог() считает сумму по данным одного объекта в памяти и не обращается к базе. СУММА() в запросе агрегирует данные по всей таблице или регистру на стороне СУБД. Для одного документа достаточно Итог(), для аналитики по множеству документов нужен запрос.

Как вывести общий итог в динамическом списке?

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

Почему сумма в моем отчете не совпадает с типовым отчетом?

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

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

Да, через конструкцию ВЫБОР: СУММА(ВЫБОР КОГДА Условие ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ). Так можно в одном запросе получить несколько сумм по разным условиям без дополнительных обращений к базе.

Итог

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

Способ расчета суммы выбирается по месту хранения данных: Итог() — для табличной части, СУММА() в запросе — для регистров и больших объемов, ресурсы — для отчетов СКД. Всегда обрабатывайте NULL, проверяйте дублирование строк при соединениях и сверяйте результат с независимым контрольным значением.