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