Разработка и Конфигурация · 10 мин
Как в 1С посчитать сумму строк: запросы, таблицы значений и отчёты
Как посчитать сумму строк в 1С: через запрос с ИТОГИ, свёртку таблицы значений, цикл по строкам и итоги в СКД. Примеры кода, ошибки и проверка результата.
Задача посчитать сумму строк встречается в 1С постоянно: нужно получить итог по колонке табличной части документа, сложить значения в таблице значений, вывести сумму в отчёте или в запросе. Универсального одного способа нет — выбор зависит от того, где находятся данные: в запросе, в таблице значений, в табличной части объекта или в отчёте на СКД.
Каждый подход имеет свои ограничения. Запрос с итогами быстр и не грузит память, но требует понимания группировок. Метод Итог() у таблицы значений прост, но работает только с уже загруженными данными. Цикл по строкам даёт максимальную гибкость, но медленнее на больших объёмах. Ниже разобраны все основные варианты с готовым кодом и критериями выбора.
Примеры приведены на встроенном языке 1С и подходят для платформы 8.3, как для управляемых, так и для обычных форм. Перед применением кода в рабочей базе проверьте его на копии — особенно если суммы участвуют в проведении документов или расчётах с контрагентами.
Как выбрать способ подсчёта суммы
Прежде чем писать код, определите, где физически находятся данные. Если они ещё в базе и их нужно только просуммировать — правильнее всего сделать это запросом: СУБД выполнит агрегацию быстрее, чем платформа переберёт строки в цикле. Если данные уже выгружены в таблицу значений или табличную часть — используйте встроенные методы этих объектов.
Второй критерий — нужна ли одна итоговая цифра или суммы по группам. Для одной суммы достаточно Итог() или СУММА() без группировки. Для сумм по контрагентам, номенклатуре или периодам потребуется группировка в запросе либо метод Свернуть() у таблицы значений.
Как выбрать действие
Сумма строк в запросе через СУММА и ИТОГИ
Запрос — основной инструмент, когда данные хранятся в регистрах или документах. Агрегатная функция СУММА() складывает значения поля по всем строкам выборки. Если не указать группировку, получите одну итоговую строку с общей суммой.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СУММА(ПродажиОбороты.СуммаОборот) КАК СуммаОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
ОбщаяСумма = Результат.СуммаОборот;
КонецЕсли;
Когда нужны суммы по группам и общий итог одновременно, добавьте конструкцию ИТОГИ ПО. Тогда в результате появятся итоговые записи по каждой группе, а обход выполняется методом Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Это удобно для печатных форм, где суммы выводятся по каждому контрагенту и в конце документа.
Сумма по табличной части документа запросом
Если нужно просуммировать строки табличной части конкретного документа, обратитесь к ней через точку: Документ.РеализацияТоваровУслуг.Товары. Отбор по ссылке ограничит выборку одним документом, а СУММА(Товары.Сумма) даст итог без загрузки всего объекта в память.
Сумма колонки таблицы значений методом Итог()
У таблицы значений и табличной части есть встроенный метод Итог("ИмяКолонки"). Он возвращает сумму всех значений числовой колонки одной строкой кода — без циклов и запросов. Это самый короткий способ, когда данные уже находятся в памяти.
// Табличная часть документа
СуммаДокумента = Объект.Товары.Итог("Сумма");
// Таблица значений, заполненная программно
ИтогоПоТаблице = ТаблицаРезультат.Итог("Сумма");
Ограничение метода: колонка должна иметь числовой тип. Если колонка составного типа (число и строка), платформа может выдать ошибку или некорректный результат. Проверить тип колонки можно через ТаблицаЗначений.Колонки.Найти("Сумма").ТипЗначения.
Суммы по группам: метод Свернуть()
Когда из таблицы значений нужны суммы в разрезе групп — например, по контрагенту или складу — используйте Свернуть(). Метод группирует строки по указанным колонкам и суммирует числовые колонки, перечисленные вторым параметром.
ТаблицаИтогов = ТаблицаДанных.Скопировать();
ТаблицаИтогов.Свернуть("Контрагент", "Сумма, Количество");
// Теперь в ТаблицаИтогов одна строка на каждого контрагента
// с суммами по колонкам Сумма и Количество
Обратите внимание: Свернуть() изменяет саму таблицу, к которой применён. Если исходные детальные строки ещё нужны, работайте с копией, как в примере выше. Все колонки, не указанные ни в группировке, ни в суммируемых, будут удалены из результата.
Подсчёт суммы в цикле с условиями
Цикл по строкам оправдан, когда суммировать нужно не всё подряд, а по условию: только строки с определённым признаком, только проведённые, только с ненулевым количеством. Также цикл нужен, если сумма вычисляется из нескольких полей или требует промежуточных расчётов.
ИтоговаяСумма = 0;
Для Каждого СтрокаТовара Из Объект.Товары Цикл
Если СтрокаТовара.Отменено Тогда
Продолжить; // отменённые строки не учитываем
КонецЕсли;
ИтоговаяСумма = ИтоговаяСумма + СтрокаТовара.Сумма;
КонецЦикла;
Минус подхода — производительность. На таблице в несколько десятков тысяч строк цикл в коде заметно уступает запросу. Если условие можно выразить в запросе через ГДЕ, перенесите фильтрацию туда, а сумму получите через СУММА().
Сумма в отчёте на СКД без кода
Если сумма нужна в отчёте, программировать вообще не обязательно. В схеме компоновки данных достаточно на закладке «Ресурсы» добавить поле с выражением Сумма(СуммаОборот). СКД сама рассчитает итоги по каждой группировке отчёта и общий итог, а пользователь сможет менять группировки без доработки кода.
В макете СКД итоги по группам выводятся автоматически, если у ресурса установлена агрегатная функция. Для суммирования по иерархии (например, по папкам номенклатуры) включите расчёт итогов по иерархии в настройках группировки — тогда сумма посчитается с учётом вложенных элементов.
Проверяйте итог на контрольном примере: возьмите документ с двумя-тремя строками, сумму которых легко посчитать вручную, и сравните с результатом кода. Это быстрее, чем искать ошибку на большом объёме данных.
Проверка результата и типичные проблемы
После расчёта убедитесь, что сумма соответствует ожиданиям. Самый надёжный способ — сопоставить программный итог с данными, видимыми пользователю: итогом по колонке в форме документа или стандартным отчётом по тому же регистру за тот же период.
Расхождения чаще всего возникают из-за трёх причин: разных отборов (в запросе и в отчёте отличаются параметры периода или организации), неучтённых NULL-значений и округления. Если суммы расходятся на копейки — проверьте, где применяется Окр() и в каком порядке выполняются операции умножения и округления.
Как проверить результат
Итог по коду совпадает с итогом колонки в форме
Расхождение — проверьте отборы и условия в коде
Колонка имеет тип Число
Составной тип — возможны ошибки Итог()
Поля заполнены или обёрнуты в ЕСТЬNULL
Строки с NULL выпадают из суммы
Все суммы в одной валюте
Смешанные валюты — требуется пересчёт по курсу
Что важно запомнить
Для данных в базе используйте запрос с СУММА() и ИТОГИ — это самый быстрый способ. Для таблиц значений и табличных частей подходят Итог() и Свернуть(). Цикл оставьте для условий и нестандартных расчётов. В отчётах суммы считайте ресурсами СКД без кода. Результат всегда сверяйте с контрольным примером.
Частые вопросы
Как посчитать сумму только по выделенным строкам табличной части?
Стандартного метода для выделенных строк нет. Получите массив выделенных строк через Элементы.Товары.ВыделенныеСтроки, затем в цикле найдите каждую строку по идентификатору (Объект.Товары.НайтиПоИдентификатору()) и накопите сумму. Для формы списка логика аналогична.
Почему Итог() возвращает 0, хотя колонка заполнена?
Наиболее вероятная причина — значения колонки имеют строковый тип, а не числовой. Это бывает, когда таблица значений заполнена из текста или файла без явного указания типа колонки. Проверьте ТипЗначения колонки и при необходимости создайте колонку с квалификатором Новый ОписаниеТипов("Число").
Как посчитать сумму с учётом иерархии в запросе?
Добавьте в секцию итогов указание ИТОГИ СУММА(Сумма) ПО Номенклатура ИЕРАРХИЯ. Тогда платформа рассчитает суммы по каждому уровню иерархии справочника. Учтите, что для избежания задвоения при соединениях иногда требуется ИТОГИ ПО ОБЩИЕ или корректная настройка группировок в СКД.
Что быстрее: Итог() по таблице или запрос?
Если данные ещё не загружены из базы — запрос однозначно быстрее, так как агрегацию выполняет СУБД. Если таблица уже в памяти, вызов Итог() дёшев и дополнительный запрос только добавит лишнее обращение к базе. Выбирайте по месту нахождения данных, а не по абстрактной скорости.
Как вывести сумму колонки в подвал динамического списка?
У динамического списка нет встроенного автоматического итога по колонке. Варианты: рассчитать сумму отдельным запросом с теми же отборами и вывести в поле на форме, либо перевести вывод в отчёт на СКД, где итоги по ресурсам считаются автоматически. Второй вариант предпочтительнее при сложных отборах пользователя.
Можно ли просуммировать строки результата запроса без выгрузки в таблицу?
Да. Получите выборку через Выбрать() и в цикле Пока Выборка.Следующий() накапливайте сумму. Но если нужна только сумма, правильнее сразу написать запрос с СУММА() — тогда СУБД вернёт одну строку с готовым итогом, и перебор не понадобится вовсе.