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