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

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

Как вывести итоги из запроса 1С

Разбираем, как вывести итоги из запроса 1С: конструкция ИТОГИ ПО, итоги по группировкам и периодам, обход выборки, типичные ошибки и проверка результата.

Итоги в запросе 1С нужны, когда требуется не просто получить детальные строки, а посчитать суммы, количества или средние значения по группам — например, обороты по контрагентам, остатки по складам или продажи по месяцам. В языке запросов для этого служат агрегатные функции (СУММА, КОЛИЧЕСТВО, МАКСИМУМ и другие) в сочетании с предложениями СГРУППИРОВАТЬ ПО и ИТОГИ ПО.

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

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

Два способа получить итоги: группировка или ИТОГИ ПО

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

Второй способ — предложение ИТОГИ ПО. Запрос возвращает и детальные строки, и итоговые записи по указанным измерениям, причём итоговые строки образуют иерархию. Это удобно для отчётов вида «группа → детализация»: например, склад и под ним все товары с остатками.

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

Сравнение подходов

СГРУППИРОВАТЬ ПО + агрегаты

Одна строка на группу, простой обход. Не подходит, если нужны детальные строки рядом с итогом.

ИТОГИ ПО

Детали плюс иерархические итоги одним запросом. Требует обхода с типом ПоГруппировкам, сложнее в коде.

Ручной подсчёт в цикле

Гибко для нестандартной логики, но медленно на больших объёмах и легко допустить ошибку. Только как исключение.

Итоги через СГРУППИРОВАТЬ ПО и агрегатные функции

Базовый пример — сумма продаж по контрагентам:

ВЫБРАТЬ

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

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

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

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

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

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

Типичная ловушка — КОЛИЧЕСТВО вместо КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...). Если нужно посчитать число уникальных документов, а не строк табличных частей, обязательно используйте вариант с РАЗЛИЧНЫЕ, иначе документ с пятью строками будет посчитан пять раз.

Итоги через ИТОГИ ПО: синтаксис и пример

Предложение ИТОГИ ПО добавляется в конец запроса после УПОРЯДОЧИТЬ ПО. Пример — остатки по складам с детализацией до номенклатуры:

ВЫБРАТЬ

Остатки.Склад КАК Склад,

Остатки.Номенклатура КАК Номенклатура,

Остатки.КоличествоОстаток КАК Количество

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Остатки

ИТОГИ

СУММА(Количество)

ПО

Склад

В секции ИТОГИ перечисляются агрегатные выражения, которые будут посчитаны в итоговых строках. В секции ПО — поля, по которым строятся группы. Уровней может быть несколько: «ИТОГИ ... ПО Склад, Номенклатура.ВидНоменклатуры» создаст двухуровневую иерархию.

Чтобы получить ещё и общий итог по всему запросу, добавьте ОБЩИЕ: «ИТОГИ СУММА(Количество) ПО ОБЩИЕ, Склад». В результате появится корневая итоговая строка с группировкой «Общие».

bsl
ВЫБРАТЬ Продажи.Номенклатура КАК Номенклатура, СУММА(Продажи.КоличествоОборот) КАК Количество ИЗ РегистрНакопления.Продажи.Обороты КАК Продажи СГРУППИРОВАТЬ ПО Продажи.Номенклатура ИТОГИ СУММА(Количество) ПО ОБЩИЕ

Обход результата запроса с итогами в коде

Результат запроса с ИТОГИ ПО нельзя обойти обычным линейным циклом — итоговые строки нужно получать через выборку по группировкам. Типовой код выглядит так:

ВыборкаСклады = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаСклады.Следующий() Цикл

Сообщить("Склад: " + ВыборкаСклады.Склад + ", итого: " + ВыборкаСклады.Количество);

ВыборкаТовары = ВыборкаСклады.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаТовары.Следующий() Цикл

// детальные строки по номенклатуре

КонецЦикла;

КонецЦикла;

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

Для общего итога обход начинается так же, но имя группировки — «Общие»: Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Общие"). Альтернатива — прямой обход результата без указания группировок, где итоговые строки определяются по ТипЗаписи() выборки.

Порядок действий
  1. 1
    Сформулируйте запрос с ИТОГИ ПО по нужному измерению
  2. 2
    Выполните запрос: Результат = Запрос.Выполнить()
  3. 3
    Получите выборку: Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам)
  4. 4
    Обойдите итоговые строки циклом Пока ... Следующий()
  5. 5
    Из каждой итоговой строки получите детальные записи вложенным Выбрать()
  6. 6
    Проверьте суммы: сравните итог с контрольной группировкой без ИТОГИ ПО

Итоги по периодам и виртуальным таблицам

Частая задача — итоги по месяцам или дням. Для этого поле периода группируется через функции НАЧАЛОПЕРИОДА или ПЕРИОД в виртуальной таблице оборотов. Например, в таблице Обороты регистра накопления периодичность задаётся параметром: Обороты(&Начало, &Конец, Месяц, ) — тогда в результате уже будет поле Период с началом месяца.

Если работаете с физической таблицей, группируйте по НАЧАЛОПЕРИОДА(Документ.Дата, МЕСЯЦ). Учтите, что записи с пустой или незаполненной датой могут попасть в отдельную группу — при необходимости отфильтруйте их условием ГДЕ.

Для регистров сведений и остатков помните: итоги по остаткам суммировать по периодам нельзя — остаток на конец месяца не равен сумме остатков по дням. Используйте виртуальную таблицу Остатки с конкретной датой или ОстаткиИОбороты, где есть отдельные поля начального и конечного остатка.

Проверка результата и производительность

После написания запроса полезно проверить итоги независимым способом. Самый простой контроль — выполнить тот же запрос с группировкой без ИТОГИ ПО и сверить суммы по группам. Для регистров накопления итоги можно сверить со стандартным отчётом конфигурации по тому же регистру за тот же период.

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

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

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

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

Сумма по группе
Норма

Совпадает с результатом того же запроса через СГРУППИРОВАТЬ ПО

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

Расходится — вероятно, соединение размножает строки

Структура выборки
Норма

Итоговые строки читаются через ПоГруппировкам, детали — вложенной выборкой

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

Выборка пустая или падает ошибка — неверный тип обхода или имя группировки

NULL в итогах
Норма

Пустые значения обработаны через ЕСТЬNULL

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

В итогах пропуски или неожиданные NULL

Типичные ошибки при выводе итогов

Самая распространённая ошибка — попытка обойти результат с ИТОГИ ПО линейным циклом и удивление, откуда взялись «лишние» строки с пустыми измерениями. Это и есть итоговые строки: при линейном обходе они тоже присутствуют, и их нужно отфильтровывать по ТипЗаписи() или сразу использовать обход по группировкам.

Вторая частая проблема — поле итога не указано в секции ИТОГИ. Если написать «ИТОГИ ПО Склад», не перечислив агрегаты, итоговые суммы будут NULL. Всегда явно указывайте, что именно суммировать: ИТОГИ СУММА(Количество), СУММА(Сумма) ПО Склад.

Третья ошибка — использование ИТОГИ ПО по полю, которое может быть NULL или пустой ссылкой: такие записи собираются в отдельную группу с пустым значением измерения, что выглядит в отчёте как «странная» строка. Решение — отфильтровать их условием ГДЕ или обработать в коде.

Типичные ошибки
01
Линейный обход результата с ИТОГИ ПО — итоговые строки попадают в обработку как детальные
02
ИТОГИ ПО без перечисления агрегатов — итоговые поля равны NULL
03
СУММА по таблице после соединения один-ко-многим — задвоенные итоги
04
Суммирование остатков по периодам вместо оборотов — бессмысленные цифры
05
КОЛИЧЕСТВО вместо КОЛИЧЕСТВО(РАЗЛИЧНЫЕ) при подсчёте документов

FAQ: частые вопросы об итогах в запросах 1С

Как получить только общий итог по всему запросу без деталей?

Проще всего использовать агрегатную функцию без группировки: ВЫБРАТЬ СУММА(Сумма) ИЗ ... — запрос вернёт одну строку с общей суммой. Если запрос уже содержит ИТОГИ ПО, добавьте ОБЩИЕ в список группировок и читайте выборку с группировкой «Общие».

Чем отличается ИТОГИ ПО от СГРУППИРОВАТЬ ПО?

СГРУППИРОВАТЬ ПО сворачивает результат до одной строки на группу и не содержит детальных записей. ИТОГИ ПО сохраняет все детальные строки и добавляет к ним иерархические итоговые записи, которые обходятся через ОбходРезультатаЗапроса.ПоГруппировкам.

Почему в итоговой строке поле измерения пустое?

Это нормально: в итоговой строке значения измерений нижних уровней не заполняются. Но если пустое значение появилось в группе верхнего уровня — вероятно, в данных есть записи с NULL или пустой ссылкой в поле группировки. Отфильтруйте их условием ГДЕ.

Можно ли вывести итоги по нескольким полям сразу?

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

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

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

Что быстрее: ИТОГИ ПО или свёртка таблицы значений в коде?

Почти всегда быстрее ИТОГИ ПО или группировка, потому что агрегация выполняется на стороне СУБД без передачи детальных строк на сервер 1С. Свёртка таблицы значений в коде оправдана только при нестандартной логике, которую нельзя выразить в запросе.

Итог

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

Для одной строки на группу используйте СГРУППИРОВАТЬ ПО с агрегатными функциями; для иерархии «группа + детали» — ИТОГИ ПО с обходом ПоГруппировкам. Суммируйте обороты, а не остатки, проверяйте соединения на размножение строк и сверяйте итоги контрольным запросом.