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

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

Как получить сумму табличной части в 1С

Как посчитать сумму колонки табличной части документа в 1С: циклом, методом Итог(), запросом, в форме и в запросах. Примеры кода, ошибки и проверка результата.

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

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

Ниже разобраны рабочие варианты с примерами кода, условиями выбора, типичными ошибками и способами проверить, что сумма посчитана правильно. Примеры приведены для управляемых и обычных форм, синтаксис актуален для платформы 8.3.

Способ 1. Метод Итог() — самый короткий вариант

У табличной части объекта есть встроенный метод Итог(), который возвращает сумму по указанной колонке без единой строчки цикла. Это предпочтительный способ, когда нужно просуммировать все строки без условий.

// В модуле объекта или формы документа

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

КоличествоВсего = Объект.Товары.Итог("Количество");

Метод работает и в общих модулях, если передать туда ссылку на документ и получить объект:

ДокументОбъект = ДокументСсылка.ПолучитьОбъект();

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

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

Способ 2. Перебор строк в цикле — когда нужны условия

Цикл применяется, если суммировать нужно не все строки, а только подходящие по условию: с определённым складом, конкретной номенклатурной группой, ненулевым количеством и т.п.

СуммаСоСклада = 0;

Для Каждого СтрокаТовары Из Объект.Товары Цикл

Если СтрокаТовары.Склад = СкладОтбора Тогда

СуммаСоСклада = СуммаСоСклада + СтрокаТовары.Сумма;

КонецЕсли;

КонецЦикла;

Тот же приём используют, когда одновременно со суммой нужно что-то сделать со строками — проставить признак, пересчитать цену, собрать список номенклатуры. Один проход по строкам решает несколько задач.

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

Типичные ошибки
01
Не обнулить переменную-накопитель перед циклом: при повторном вызове процедуры сумма удваивается
02
Сравнивать ссылочные реквизиты строки по строковому представлению вместо сравнения ссылок — условие никогда не срабатывает
03
Использовать цикл там, где достаточно Итог(): лишний код сложнее поддерживать
04
Суммировать колонку, в которой могут быть пустые значения, без проверки — на некоторых сценариях получите ошибку или искажённый итог

Способ 3. Запрос с функцией СУММА()

Если документ уже записан в базу и нужно получить сумму без открытия объекта, правильнее использовать запрос к табличной части. Табличные части документов доступны в запросах как отдельные таблицы с префиксом вида Документ.РеализацияТоваровУслуг.Товары.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| СУММА(Товары.Сумма) КАК СуммаДокумента,

| СУММА(Товары.Количество) КАК КоличествоДокумента

|ИЗ

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

|ГДЕ

| Товары.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

Итог = Выборка.СуммаДокумента;

КонецЕсли;

Запрос незаменим, когда нужно посчитать суммы сразу по группе документов, сгруппировать итоги по номенклатуре или контрагенту, либо когда код выполняется в фоновом задании без формы. Дополнительно через ИМЕЮЩИЕ и СГРУППИРОВАТЬ ПО решаются задачи аналитики, не влезающие в цикл.

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

bsl
ВЫБРАТЬ ЕСТЬNULL(СУММА(Товары.Сумма), 0) КАК СуммаДокумента ИЗ Документ.РеализацияТоваровУслуг.Товары КАК Товары ГДЕ Товары.Ссылка = &Ссылка

Как вывести итог в подвале табличной части на форме

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

Порядок действий
  1. 1
    Откройте форму документа в конфигураторе и выделите колонку табличной части, по которой нужен итог
  2. 2
    В свойствах колонки установите ОтображатьВПодвале = Истина и выберите функцию итога (Сумма)
  3. 3
    У самой таблицы проверьте свойство отображения подвала (Подвал = Истина)
  4. 4
    Сохраните форму и откройте документ в режиме предприятия — итог должен пересчитываться при изменении строк

В типовых конфигурациях итог по колонкам «Сумма» и «Количество» обычно уже включён. Если подвал не виден, чаще всего выключено отображение подвала у всей таблицы, а не у колонки.

В обычных формах (толстый клиент) механика аналогична: у колонки табличного поля есть свойства «ОтображатьИтогиВПодвале» и «ИтогиВПодвале». Программно итог обновляется автоматически, ручной пересчёт не требуется.

Сумма в форме через данные табличной части

Когда итог нужен как реквизит формы — например, чтобы вывести «Итого к оплате» отдельным полем или использовать в условиях видимости кнопок, — сумму считают в коде формы и помещают в реквизит.

&НаКлиенте

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

ПересчитатьИтог();

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

&НаСервере

Процедура ПересчитатьИтог()

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

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

Здесь важно не перегружать форму серверными вызовами. Если пересчёт итога — единственная логика, выполняйте его на клиенте циклом по строкам, чтобы не делать лишний обмен с сервером при каждом изменении строки. Метод Итог() на клиенте в управляемой форме для данных формы типа «табличная часть объекта» доступен.

Маршрут решения

Как выбрать способ

Нужна сумма всех строк одной колонки в кодеИспользуйте Объект.Товары.Итог("Сумма")
Нужна сумма с условием по строкамЦикл с проверкой условия или запрос с ГДЕ
Документ записан, объект открывать нельзя или нужны итоги по группе документовЗапрос с СУММА() к табличной части
Нужно просто показать итог пользователю под таблицейВключите итог по колонке в свойствах формы, код не нужен

Проверка результата и типичные расхождения

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

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

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

Сравнение с подвалом формы
Норма

Числа совпадают до копейки

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

Расхождение — проверяйте условие отбора и состав колонки

Пустой документ
Норма

Итог равен 0, ошибок нет

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

NULL или ошибка выполнения — добавьте ЕСТЬNULL или проверку

Документ с несколькими строками и дробными суммами
Норма

Итог сходится при ручном сложении

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

Копеечные расхождения — проблема округления в строках

Повторный вызов процедуры
Норма

Сумма не меняется

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

Сумма растёт — переменная-накопитель не обнуляется

Отдельная ситуация — расхождение суммы табличной части с реквизитом «Сумма документа» в шапке. В типовых конфигурациях этот реквизит пересчитывается в обработчиках проведения или перед записью. Если документ редактировали программно без вызова стандартных процедур пересчёта, итоги разойдутся. Проверить это можно запросом, сравнив СУММА() табличной части с реквизитом шапки по списку документов.

Производительность на больших табличных частях

Для документов с сотнями и тысячами строк выбор способа влияет на скорость. Метод Итог() реализован на уровне платформы и работает быстрее цикла на встроенном языке. Запрос быстрее обоих, если данные нужно взять из базы без загрузки объекта целиком: ПолучитьОбъект() читает все табличные части документа, а запрос — только нужную колонку.

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

Итог

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

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

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

Как посчитать сумму по нескольким колонкам сразу?

Вызовите Итог() для каждой колонки отдельно: Объект.Товары.Итог("Сумма") и Объект.Товары.Итог("Количество"). В запросе перечислите несколько агрегатов СУММА() в одном ВЫБРАТЬ — это один запрос к базе.

Почему Итог() возвращает неправильное значение после удаления строк?

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

Как посчитать сумму табличной части в СКД или отчёте?

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

Можно ли получить сумму без открытия объекта документа?

Да, через запрос к таблице Документ.ВидДокумента.ИмяТабличнойЧасти с отбором по ссылке. Это быстрее и безопаснее, чем ПолучитьОбъект(), особенно в фоновых и регламентных операциях.

Что делать, если в колонке могут быть нечисловые значения?

Проверьте тип данных колонки в конфигураторе. Если тип составной, приводите значение в цикле через проверку ТипЗнч() или суммируйте только числовые значения, иначе получите ошибку преобразования.

Как округлить итог до копеек?

Используйте функцию Окр(Сумма, 2) после расчёта. Но если расхождения копеечные возникают из-за цен с большим числом знаков, правильнее настроить округление на уровне строк документа, а не только итога.