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