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

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

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

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

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

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

Ниже разобраны основные способы суммирования строк: предложение ИТОГИ в языке запросов, метод Свернуть() для таблиц значений, вычисление суммы по табличной части документа, настройка итогов в СКД и динамических списках, а также типичные ошибки и способы проверки результата.

Суммирование в запросе: СУММА, группировка и ИТОГИ

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

| Продажи.Проведен

|

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

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

Если нужны не только итоги по группам, но и сами детальные строки, используется предложение ИТОГИ. Оно добавляет в результат итоговые записи по указанным измерениям и общий итог (ИТОГИ ПО ОБЩИЕ). Для обхода такого результата применяется метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам), иначе итоговые строки будут обработаны как обычные данные.

Важное ограничение: СУММА() игнорирует значения NULL, но если все значения в группе равны NULL, результат тоже будет NULL, а не ноль. Чтобы не получить пустую сумму в дальнейших расчётах, оборачивайте поле в ЕСТЬNULL() или проверяйте результат перед использованием.

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

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

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

ОбщаяСумма = ТаблицаТоваров.Итог("Сумма");

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

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

ТаблицаКопия = ТаблицаТоваров.Скопировать();

ТаблицаКопия.Свернуть("Номенклатура, Склад", "Количество, Сумма");

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

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

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

Функция СуммаДокумента(Объект)

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

Возврат ИтогоСумма;

КонецФункции

Если нужно просуммировать только часть строк — например, только товары определённого вида или с заполненной скидкой — метод Итог() не подходит, потому что не принимает условий. Здесь два варианта: обойти строки циклом с проверкой условия, либо выгрузить табличную часть в таблицу значений через Выгрузить() и дальше работать с ней. При большом количестве строк цикл обычно проще и не требует дополнительной памяти.

Частая задача — пересчёт суммы строки при изменении цены или количества. Это делается в обработчиках событий формы ПриИзменении соответствующих полей: в обработчике берётся текущая строка через Элементы.Товары.ТекущиеДанные и пересчитывается произведение. Не пересчитывайте сумму в цикле по всем строкам при изменении одной — это замедляет работу формы на больших документах.

Порядок действий при пересчёте строки
  1. 1
    Создайте обработчик ПриИзменении для полей Количество и Цена табличной части.
  2. 2
    В обработчике получите текущую строку: Строка = Элементы.Товары.ТекущиеДанные.
  3. 3
    Присвойте Строка.Сумма = Строка.Количество * Строка.Цена с учётом скидки, если она есть.
  4. 4
    Если в подвале формы выводится итог — обновите его через Объект.Товары.Итог("Сумма").
  5. 5
    Проверьте на документе с несколькими строками: изменение одной строки не должно трогать остальные.

Суммирование в отчётах на СКД

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

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

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

Итоги в динамических списках и формах

В управляемых формах для таблиц и динамических списков можно вывести итог в подвале: у колонки формы есть свойство «Отображать в подвале» (FooterVisible / показ итога). Для обычной таблицы формы, связанной с таблицей значений, итог подсчитывается автоматически. Для динамического списка автоматический итог по всему набору данных платформа не считает — это связано с тем, что список читает данные порциями.

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

Сравнение способов суммирования

Запрос с СУММА и ИТОГИ

Самый быстрый для данных в базе; требует знания языка запросов и корректной группировки.

ТаблицаЗначений.Свернуть()

Удобен для данных уже в памяти; удаляет колонки вне группировки, работайте с копией.

ТабличнаяЧасть.Итог()

Простейший вариант для документа; не поддерживает условия отбора строк.

Ресурсы СКД

Без кода, автоматические итоги по группировкам; ошибки обычно связаны со связями наборов данных.

Цикл по строкам

Максимальная гибкость и условия любой сложности; медленнее и больше кода.

Проверка результата и границы безопасной работы

Любое суммирование стоит проверять на контрольном примере. Возьмите несколько строк с известными значениями, посчитайте сумму вручную и сравните с результатом кода. Для запросов с ИТОГИ дополнительно проверьте, что сумма по группам сходится с общим итогом — расхождение указывает на задвоение строк в соединениях или на NULL-значения.

При работе с большими объёмами тестируйте сначала на копии базы или с отбором по одному контрагенту или периоду. Метод Свернуть() изменяет таблицу на месте, а запросы с группировкой по большим регистрам могут выполняться долго и блокировать работу других пользователей, если запускать их в транзакции.

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

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

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

Сумма по группам против общего итога
Норма

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

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

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

Тип колонки перед Итог()
Норма

Колонка имеет тип Число

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

Составной тип или строки — метод падает с ошибкой

Сверка с типовым отчётом
Норма

Суммы совпадают с отчётом конфигурации за тот же период

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

Разница — проверяйте отборы по периоду, организации, проведению

Поведение Свернуть()
Норма

Сворачивается копия таблицы, исходные данные целы

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

Свёрнута рабочая таблица — колонки и детальные строки потеряны

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

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

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

Как просуммировать строки с условием, например только по одному складу?

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

Метод Свернуть() удалил нужные колонки — как восстановить?

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

Как вывести общий итог в отчёте СКД, если он пустой?

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

Что быстрее: Свернуть() или запрос с группировкой?

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

Итог

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

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