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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

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

Использование встроенного метода Итог() таблицы значений

В платформе 1С:Предприятие для объекта ТаблицаЗначений предусмотрен встроенный метод Итог(). Он принимает в качестве параметра имя числовой колонки и возвращает сумму значений всех строк этой колонки.

Синтаксис вызова метода выглядит следующим образом:


// Получаем итоговую сумму по колонке "Сумма"
ИтоговаяСумма = ТаблицаДанных.Итог("Сумма");

Если таблица значений уже находится внутри существующей структуры под ключом ТабЧасть, мы можем обратиться к ней напрямую через точку и сразу записать результат в новый параметр этой же структуры:


СтруктураПараметров.Вставить("ИтогоПоДоговору", СтруктураПараметров.ТабЧасть.Итог("Сумма"));

Анализ практического примера и исправление ошибки производительности

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

Нередко разработчики применяют следующую конструкцию:


Функция Печать() Экспорт
    СтруктураПараметров = ПолучитьДанныеЗаказПокупателя(СсылкаНаОбъект, Ложь);
    СтруктураПараметров.Вставить("ТабЧасть", ПолучитьТабЧасть());
    СтруктураПараметров.Вставить("ИтогоПоДоговору", ПолучитьТабЧасть().Итог("Сумма"));
    
    Обработки.франПечатьДоговораОбслуживания.ПечатьДокументаВФорматеWORD(ПолучитьМакет("ДоговорПоставки"), СтруктураПараметров);
КонецФункции

Проанализируем эту ситуацию: при таком подходе функция ПолучитьТабЧасть() вызывается дважды. Это означает, что тяжелый запрос к базе данных, выполняющий объединение табличных частей товаров и услуг, выполнится два раза подряд. Это приводит к лишней нагрузке на СУБД и замедлению формирования печатной формы.

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


Функция Печать() Экспорт
    СтруктураПараметров = ПолучитьДанныеЗаказПокупателя(СсылкаНаОбъект, Ложь);
    
    // Получаем таблицу значений один раз
    ТабличнаяЧасть = ПолучитьТабЧасть();
    
    // Передаем саму таблицу и рассчитанный итог
    СтруктураПараметров.Вставить("ТабЧасть", ТабличнаяЧасть);
    СтруктураПараметров.Вставить("ИтогоПоДоговору", ТабличнаяЧасть.Итог("Сумма"));
    
    Обработки.франПечатьДоговораОбслуживания.ПечатьДокументаВФорматеWORD(ПолучитьМакет("ДоговорПоставки"), СтруктураПараметров);
КонецФункции

Оптимизация заполнения номеров строк и подсчета итогов

Посмотрим на реализацию функции формирования данных. В исходном варианте для нумерации строк и подсчета суммы использовался явный цикл обхода:


Функция ПолучитьТабЧасть() 
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    0 КАК НомерПП,
    |    ВЫБОР
    |        КОГДА (ВЫРАЗИТЬ(ЗаказПокупателяТовары.Номенклатура.НаименованиеПолное КАК СТРОКА(2))) = """"
    |            ТОГДА ЗаказПокупателяТовары.Номенклатура.НаименованиеПолное
    |        ИНАЧЕ ЗаказПокупателяТовары.Номенклатура.Наименование
    |    КОНЕЦ КАК Номенклатура,
    |    ЗаказПокупателяТовары.Цена КАК Цена,
    |    ЗаказПокупателяТовары.Количество КАК Количество,
    |    ВЫБОР
    |        КОГДА ЗаказПокупателяТовары.Ссылка.СуммаВключаетНДС = ИСТИНА
    |            ТОГДА ЗаказПокупателяТовары.Сумма
    |        ИНАЧЕ ЗаказПокупателяТовары.Сумма + ЗаказПокупателяТовары.СуммаНДС
    |    КОНЕЦ КАК Сумма
    |ИЗ
    |    Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателяТовары
    |ГДЕ
    |    ЗаказПокупателяТовары.Ссылка = &СсылкаНаОбъект
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    |    0 КАК НомерПП,
    |    ЗаказПокупателяУслуги.Содержание,
    |    ЗаказПокупателяУслуги.Цена,
    |    ЗаказПокупателяУслуги.Количество,
    |    ВЫБОР
    |        КОГДА ЗаказПокупателяУслуги.Ссылка.СуммаВключаетНДС = ИСТИНА
    |            ТОГДА ЗаказПокупателяУслуги.Сумма
    |        ИНАЧЕ ЗаказПокупателяУслуги.Сумма + ЗаказПокупателяУслуги.СуммаНДС
    |    КОНЕЦ
    |ИЗ
    |    Документ.ЗаказПокупателя.Услуги КАК ЗаказПокупателяУслуги
    |ГДЕ
    |    ЗаказПокупателяУслуги.Ссылка = &СсылкаНаОбъект";
    
    Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);
    Результат = Запрос.Выполнить();
    Товары = Результат.Выгрузить();
    
    // Ручной обход строк для простановки номеров
    НомерПП = 1;
    Для Каждого Стр Из Товары Цикл
        Стр.НомерПП = НомерПП;
        НомерПП = НомерПП + 1;
    КонецЦикла;
    
    Возврат Товары;
КонецФункции

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

Важные правила и ограничения при работе с методом Итог()

Для корректной работы метода ТаблицаЗначений.Итог() необходимо учитывать следующие технические особенности:

  1. Тип данных в колонке: Метод выполняет расчет исключительно для числовых типов данных. Если в результате объединения запросов в колонку попадет значение NULL или Неопределено, подсчет может выдать непредвиденный результат. В запросах рекомендуется использовать конструкцию ЕСТЬNULL(Поле, 0).
  2. Игнорирование фильтров: Метод Итог() всегда суммирует значения по всем строкам таблицы значений без исключения, даже если к таблице на форме был применен пользовательский отбор.
  3. Клиент-серверный контекст: Объект ТаблицаЗначений доступен только на стороне сервера, в толстом клиенте или во внешнем соединении. В тонком клиенте и веб-клиенте данный тип не поддерживается, поэтому расчет итогов необходимо выполнять в серверном контексте до передачи результатов на клиент.

Альтернативный вариант: расчет итогов в тексте запроса

Если таблица формируется только для извлечения итоговой суммы и последующего последовательного вывода строк, расчет можно перенести на уровень СУБД с помощью предложения ИТОГИ:


Запрос.Текст = 
"ВЫБРАТЬ
|   ...
|   Сумма КАК Сумма
|ИЗ
|   ...
|ИТОГИ
|   СУММА(Сумма)
|ПО
|   ОБЩИЕ";

Результат = Запрос.Выполнить();
ВыборкаОбщийИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Если ВыборкаОбщийИтог.Следующий() Тогда
    ИтоговаяСумма = ВыборкаОбщийИтог.Сумма;
КонецЕсли;

Этот способ эффективен при работе с большими объемами информации, так как агрегация данных выполняется сервером баз данных без необходимости загрузки всех строк в оперативную память сервера приложений 1С.

← На главную