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

Программист 1С v8.3 (Обычные формы)
← На главную

При построении отчетов в 1С без использования Системы компоновки данных (СКД) разработчики часто сталкиваются с необходимостью вывода промежуточных итогов. Типичный пример: вывести список автомобилей, сгруппированных по заказчикам, где в строке с именем заказчика сразу отображается общее количество его машин. В этой статье мы подробно разберем, как реализовать такую задачу несколькими способами, проанализируем ошибки и научимся правильно обходить результаты запроса.

Способ 1. Использование предложения ИТОГИ в тексте запроса

Самый эффективный и правильный метод — переложить расчет сумм на плечи встроенного языка запросов 1С и СУБД. Для этого используется конструкция ИТОГИ. Проанализируем пример кода запроса, который решает задачу автора:


ТекстЗапроса = "
|ВЫБРАТЬ
|   Заказчик,
|   МаркаАвто,
|   КоличествоАвто
|ИЗ
|   РегистрСведений.ДанныеПоАвтомобилям
|ИТОГИ
|   СУММА(КоличествоАвто)
|ПО
|   Заказчик";

В данном случае платформа автоматически создаст иерархическую структуру данных. На верхнем уровне будет находиться Заказчик, а в поле КоличествоАвто для него уже будет лежать сумма всех вложенных записей. Разберем по шагам, как правильно вывести эти данные в отчет.

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

Многие начинающие программисты совершают ошибку, пытаясь перебирать результат запроса с итогами обычным линейным циклом. В этом случае данные будут дублироваться. Чтобы получить корректный отчет (как в макете), нам необходимо использовать метод Выбрать с параметром ОбходРезультатаЗапроса.ПоГруппировкам. Рассмотрим подробнее программную реализацию:


РезультатЗапроса = Запрос.Выполнить();

// Начинаем обход с верхнего уровня — Заказчики
ВыборкаЗаказчик = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаЗаказчик.Следующий() Цикл
    // Здесь ВыборкаЗаказчик.КоличествоАвто уже содержит СУММУ всех машин заказчика
    ОбластьЗаказчик = Макет.ПолучитьОбласть("ШапкаГруппировки");
    ОбластьЗаказчик.Параметры.Заполнить(ВыборкаЗаказчик);
    ТабДок.Вывести(ОбластьЗаказчик);
    
    // Вложенный обход для детальных записей (конкретные марки авто)
    ВыборкаДетали = ВыборкаЗаказчик.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
        ОбластьСтрока.Параметры.Заполнить(ВыборкаДетали);
        ТабДок.Вывести(ОбластьСтрока);
    КонецЦикла;
КонецЦикла;

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

Способ 3. Программная свертка в Таблице значений

Иногда возникает ситуация, когда запрос менять нельзя или данные поступают из разных источников. В таком случае мы можем использовать объект ТаблицаЗначений. Выясним, как это работает. Допустим, мы выгрузили результат запроса в таблицу:


ТЗ = РезультатЗапроса.Выгрузить();
// Копируем таблицу для получения итогов
ТЗИтоги = ТЗ.Скопировать();
// Схлопываем данные по заказчику, суммируя количество
ТЗИтоги.Свернуть("Заказчик", "КоличествоАвто");

Теперь у нас есть две таблицы: одна с детальными данными, другая — с готовыми итогами по каждому заказчику. Мы можем обращаться к ТЗИтоги через метод Найти, чтобы получить сумму при выводе каждой секции отчета.

Способ 4. Ручной расчет при выводе в табличный документ

Если вам требуется максимальный контроль или вы используете очень специфическую логику расчета, можно накапливать сумму вручную. Однако здесь есть важный нюанс: если итог должен быть в шапке (над марками машин), вам придется сначала «прочитать» все записи по заказчику, посчитать сумму и только потом выводить области. Проанализируем алгоритм:

  1. Создаем временную таблицу или массив для хранения строк текущего заказчика.
  2. В цикле обхода выборки накапливаем значение в переменную ИтогоПоЗаказчику.
  3. По завершении сбора данных по одному заказчику — выводим сначала область шапки с итогом, а затем накопленные строки из временного хранилища.

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

Способ 5. Визуализация и группировка строк (плюсики)

Чтобы отчет был не просто списком, а удобным инструментом, используем методы визуальной группировки табличного документа. Это позволит пользователю сворачивать и разворачивать списки машин под заказчиками. Посмотрим на пример кода:


ТабДок.НачатьГруппировкуСтрок("ГруппировкаЗаказчика", Истина);
// Вывод строк с марками машин
ТабДок.ЗакончитьГруппировкуСтрок();

Важный момент: использование методов НачатьГруппировкуСтрок и ЗакончитьГруппировкуСтрок совместно с иерархическим обходом (Способ 2) превращает обычный отчет в интерактивный инструмент, похожий на стандартные отчеты типовых конфигураций.

Анализ типичных ошибок (Почему нельзя использовать ВЫБОР в ИТОГАХ)

Разберем ситуацию, упомянутую в обсуждении на форуме. Попытка написать в блоке ИТОГИ конструкцию вида ВЫБОР КОГДА Номенклатура ЕСТЬ NULL ТОГДА... приведет к ошибке выполнения запроса. Запомним правило: в предложении ИТОГИ допускаются только агрегатные функции (СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ). Любая сложная логика условий должна находиться в основной части запроса (в блоке ВЫБРАТЬ), а итоги лишь агрегируют уже вычисленные поля.

Также стоит упомянуть ключевое слово ОБЩИЕ. Если в конце запроса написать ИТОГИ СУММА(Количество) ПО ОБЩИЕ, Заказчик, то в самой первой строке выборки вы получите общую сумму автомобилей по всем заказчикам сразу. Это избавляет от необходимости заводить дополнительные переменные-счетчики в коде 1С.

← На главную