Работа с итогами в запросах 1С:Предприятие — одна из самых востребованных задач при разработке отчетов, аналитических обработок и бизнес-логики. Без правильного подхода к агрегации данных даже простой отчет по продажам может превратиться в хаос из тысяч строк, а аналитика — в рутинную обработку в Excel. В этой статье разберем 5 ключевых методов получения итогов: от базовой группировки до продвинутых техник с временными таблицами и программной постобработкой.

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

1. Базовая группировка: ИТОГИ и ГРУППИРОВКА ПО

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

Пример запроса, который возвращает сумму продаж по каждой номенклатуре за месяц:

ВЫБРАТЬ

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

СУММА(ДокументПродажи.СуммаДокумента) КАК ИтоговаяСумма,

КОЛИЧЕСТВО(ДокументПродажи.Ссылка) КАК КоличествоДокументов

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ДокументПродажи.Номенклатура = Номенклатура.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

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

Номенклатура.Наименование

Обратите внимание на ключевые моменты:

  • 🔹 В секции ВЫБРАТЬ перечисляются только те поля, которые участвуют в группировке или являются агрегатными функциями. Добавление лишних полей вызовет ошибку.
  • 🔹 Функция КОЛИЧЕСТВО без параметров вернет количество строк в группе, а с параметром (например, КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДокументПродажи.Клиент)) — количество уникальных значений.
  • 🔹 Для дат лучше использовать параметры (&НачалоПериода), а не жестко прописанные значения — это сделает запрос универсальным.
⚠️ Внимание: Если в запросе используется ЛЕВОЕ СОЕДИНЕНИЕ или ПОЛНОЕ СОЕДИНЕНИЕ, итоги могут включать группы с нулевыми значениями. Например, номенклатура, по которой не было продаж, все равно попадет в результат с суммой 0. Это часто становится причиной ошибок в отчетах.
📊 Какой тип группировки вы используете чаще?
Простая группировка по одному полю
Многомерная группировка (несколько полей)
Группировка с условиями (HAVING)
Не использую группировку

2. Многомерные итоги: группировка по нескольким полям

Когда нужно получить итоги не только по номенклатуре, но и по складам, контрагентам или периодам, используется многомерная группировка. Например, для анализа продаж по регионам и менеджерам.

Пример запроса с группировкой по трем измерениям (номенклатура, склад, месяц):

ВЫБРАТЬ

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

Склад.Наименование КАК Склад,

ВЫРАЗИТЬ(ДокументПродажи.Дата КАК Дата) КАК Месяц,

СУММА(ДокументПродажи.Количество) КАК Количество,

СУММА(ДокументПродажи.Сумма) КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ДокументПродажи.Номенклатура = Номенклатура.Ссылка

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Склады КАК Склад

ПО ДокументПродажи.Склад = Склад.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

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

Номенклатура.Наименование,

Склад.Наименование,

ВЫРАЗИТЬ(ДокументПродажи.Дата КАК Дата)

Важные нюансы многомерной группировки:

  • 📊 Порядок полей в СГРУППИРОВАТЬ ПО влияет на структуру результата. Например, если сначала группировать по складам, а потом по номенклатуре, итоги будут сгруппированы иерархически.
  • 🔄 Для работы с датами используйте функцию ВЫРАЗИТЬ, чтобы привести дату к нужному формату (день, месяц, квартал).
  • 📉 Чем больше измерений в группировке, тем дольше выполняется запрос. Для больших баз данных (>100К документов) лучше использовать временные таблицы (раздел 4).
💡

Если нужно получить итоги по иерархическим справочникам (например, группы номенклатуры), используйте функцию ИЕРАРХИЯ или виртуальную таблицу ПолнаяИерархия. Это позволит показывать итоги как по элементам, так и по группам.

3. Фильтрация групп: оператор ИМЕЮЩИЕ

Иногда требуется отфильтровать не отдельные записи, а целые группы. Например, показать только тех клиентов, которые сделали заказы на сумму больше 100 000 рублей, или номенклатуру, которая продавалась более 10 раз. Для этого используется оператор ИМЕЮЩИЕ (аналог HAVING в SQL).

Пример запроса, который возвращает только те позиции номенклатуры, которые продавались более 5 раз за период:

ВЫБРАТЬ

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

СУММА(ДокументПродажи.Количество) КАК ОбщееКоличество,

СУММА(ДокументПродажи.Сумма) КАК ОбщаяСумма

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ДокументПродажи.Номенклатура = Номенклатура.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

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

Номенклатура.Наименование

ИМЕЮЩИЕ

СУММА(ДокументПродажи.Количество) > 5

Ключевые особенности ИМЕЮЩИЕ:

  • 🎯 Оператор применяется после группировки, поэтому фильтрует уже сгруппированные данные, а не исходные записи.
  • 🔍 В условии можно использовать те же агрегатные функции, что и в секции ВЫБРАТЬ.
  • ⚠️ ИМЕЮЩИЕ не поддерживает подзапросы и некоторые сложные выражения. Для таких случаев лучше использовать временные таблицы (раздел 4).
⚠️ Внимание: В 1С:Предприятие 8.3.20+ появилась возможность использовать в ИМЕЮЩИЕ выражения с ВЫБОР КОГДА, что расширило возможности фильтрации групп. Однако в более ранних версиях это может вызвать ошибку.

4. Продвинутые техники: временные таблицы и программная обработка

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

Пример использования временной таблицы для расчета итогов с дополнительными условиями:

// Сначала создаем временную таблицу с детализированными данными

ВЫБРАТЬ

ДокументПродажи.Номенклатура КАК Номенклатура,

ДокументПродажи.Количество КАК Количество,

ДокументПродажи.Сумма КАК Сумма

ПОМЕСТИТЬ ВТ_Продажи

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

И ДокументПродажи.Склад = &ТекущийСклад

ИНДЕКСИРОВАТЬ ПО

Номенклатура;

// Затем получаем итоги из временной таблицы

ВЫБРАТЬ

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

СУММА(ВТ_Продажи.Количество) КАК ИтогКоличество,

СУММА(ВТ_Продажи.Сумма) КАК ИтогСумма

ИЗ

ВТ_Продажи КАК ВТ_Продажи

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ВТ_Продажи.Номенклатура = Номенклатура.Ссылка

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

Номенклатура.Наименование;

Преимущества временных таблиц:

  • Производительность: данные обрабатываются в два этапа, что ускоряет выполнение сложных запросов.
  • 🔧 Гибкость: можно добавлять дополнительные условия на втором этапе без пересчета исходных данных.
  • 📊 Многоэтапная аналитика: временные таблицы позволяют строить цепочки запросов, где результат одного становится источником для другого.

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

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

СУММА(ДокументПродажи.Сумма) КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ДокументПродажи.Номенклатура = Номенклатура.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

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

Номенклатура.Наименование";

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

// Рассчитываем общую сумму и доли

ОбщаяСумма = Результат.Итог("Сумма");

Для Каждого Строка Из Результат Цикл

Строка.Доля = Строка.Сумма / ОбщаяСумма * 100;

КонецЦикла;

⚠️ Внимание: При использовании временных таблиц в 1С:Предприятие 8.3.18+ появилась возможность указывать индексы (ИНДЕКСИРОВАТЬ ПО). Это значительно ускоряет соединения с временными таблицами, но требует аккуратности: неверно выбранные индексы могут, наоборот, замедлить запрос.

Убедиться, что версия платформы поддерживает нужный синтаксис|Проверить объем данных (временные таблицы эффективны для >10К строк)|Создать индексы для полей, по которым будут соединения|Ограничить данные на первом этапе (WHERE), а не на втором-->

5. Итоги по иерархиям: группы номенклатуры, подразделения, регионы

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

  • 📁 ИЕРАРХИЯ — для включения групп в результат.
  • 🔍 УРОВЕНЬ — для определения уровня вложенности.
  • 🔗 Виртуальные таблицы ПолнаяИерархия — для рекурсивного обхода иерархии.

Пример запроса, который возвращает итоги продаж по группам и элементам номенклатуры:

ВЫБРАТЬ

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

Номенклатура.ЭтотУзел КАК ЭтоГруппа,

СУММА(ДокументПродажи.Количество) КАК Количество,

СУММА(ДокументПродажи.Сумма) КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО ДокументПродажи.Номенклатура = Номенклатура.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

И Номенклатура.ПометкаУдаления = ЛОЖЬ

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

Номенклатура.Наименование,

Номенклатура.ЭтотУзел

ИЕРАРХИЯ

Номенклатура.Ссылка

Особенности работы с иерархиями:

  • 🌳 Поле ЭтотУзел равно ИСТИНА для групп и ЛОЖЬ для элементов.
  • 🔄 Для рекурсивного обхода (например, подсчета итогов по всем подгруппам) используйте виртуальную таблицу ПолнаяИерархия:
ВЫБРАТЬ

ПолнаяИерархия.Родитель КАК Группа,

СУММА(ДокументПродажи.Сумма) КАК СуммаПоГруппе

ИЗ

Справочник.Номенклатура.ПолнаяИерархия КАК ПолнаяИерархия

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК ДокументПродажи

ПО ДокументПродажи.Номенклатура = ПолнаяИерархия.Ссылка

ГДЕ

ДокументПродажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода

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

ПолнаяИерархия.Родитель

Как ускорить запросы по иерархиям?

Для больших справочников (>10К элементов) виртуальная таблица ПолнаяИерархия может работать медленно. В таких случаях:

1. Используйте ИЕРАРХИЯ только для верхних уровней иерархии.

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

3. Кэшируйте результаты иерархических запросов в временных таблицах.

6. Итоги в отчетах: связь с СКД и динамическими списками

В реальных задачах итоги редко выводятся "как есть" — обычно они интегрируются в отчеты, построенные на Системе Компоновки Данных (СКД) или динамических списках. Здесь важно понимать, как правильно передавать данные из запроса в СКД и настраивать группировки.

Пример настройки СКД для вывода итогов:

// 1. Получаем данные запросом (см. предыдущие разделы)

Запрос = Новый Запрос(ТекстЗапроса);

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

// 2. Настраиваем схему компоновки данных

СхемаКомпоновки = Новый СхемаКомпоновкиДанных;

СхемаКомпоновки.ИсточникДанных = Новый ИсточникДанныхНаборДанных(РезультатЗапроса);

// 3. Добавляем группировки

ГруппировкаНоменклатура = СхемаКомпоновки.Группировки.Добавить();

ГруппировкаНоменклатура.Поле = Новый ПолеНабораДанных("Номенклатура");

ГруппировкаНоменклатура.Итоги.Добавить(ТипИтога.Сумма, "Сумма");

// 4. Настраиваем вывод

НастройкиКомпоновки = СхемаКомпоновки.НастройкиПоУмолчанию;

НастройкиКомпоновки.Структура.Очистить();

ЭлементСтруктуры = НастройкиКомпоновки.Структура.Добавить("Номенклатура", ТипЭлементаСтруктуры.Группировка);

ЭлементСтруктуры.Поля.Добавить(Новый ПолеКомпоновкиДанных("Сумма"));

// 5. Формируем отчет

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;

ПроцессорКомпоновки.Инициализировать(СхемаКомпоновки, НастройкиКомпоновки, ДанныеРасшифровки);

РезультатКомпоновки = ПроцессорКомпоновки.Выполнить();

Ключевые моменты интеграции с СКД:

  • 📋 В схеме компоновки можно настроить многоуровневые итоги (по группам, подгруппам, элементам).
  • 🔧 Для динамического управления группировками используйте параметры компоновки (ПараметрыКомпоновкиДанных).
  • 📊 В СКД доступны дополнительные типы итогов: Среднее, Максимум, Минимум, Количество и др.
Метод получения итогов Производительность Сложность реализации Когда использовать
Базовая группировка (ГРУППИРОВКА ПО) ⭐⭐⭐⭐⭐ Простые отчеты, небольшие объемы данных
Многомерная группировка ⭐⭐⭐⭐ ⭐⭐ Аналитика по нескольким измерениям (склад, период, менеджер)
Оператор ИМЕЮЩИЕ ⭐⭐⭐ ⭐⭐ Фильтрация групп по агрегатным условиям
Временные таблицы ⭐⭐⭐⭐ ⭐⭐⭐ Сложные многоэтапные расчеты, большие объемы данных
Иерархические итоги ⭐⭐ ⭐⭐⭐⭐ Отчеты по группам номенклатуры, подразделениям, регионам
💡

Для максимальной производительности комбинируйте методы: используйте временные таблицы для предварительной обработки данных, а итоги получайте базовой группировкой. Это сократит время выполнения запроса в 2-3 раза.

Типичные ошибки и как их избежать

Даже опытные разработчики иногда сталкиваются с проблемами при работе с итогами. Вот наиболее распространенные ошибки и способы их решения:

1. Ошибка "Поле не входит в список полей группировки"

Причина: В секции ВЫБРАТЬ указано поле, которое не участвует в группировке и не является агрегатной функцией.

Решение: Добавьте поле в СГРУППИРОВАТЬ ПО или примените к нему агрегатную функцию (например, МАКСИМУМ).

2. Неправильные итоги из-за ЛЕВОГО СОЕДИНЕНИЯ

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

Решение: Используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ или фильтруйте нулевые значения с помощью ИМЕЮЩИЕ.

3. Медленное выполнение запроса с иерархией

Причина: Виртуальная таблица ПолнаяИерархия рекурсивно обходит все уровни, что требует много ресурсов.

Решение: Ограничьте глубину иерархии параметром Уровень или используйте временные таблицы для кэширования.

4. Итоги не совпадают с детализацией

Причина: В детализации могут быть скрытые фильтры (например, по дате или статусу документа), которые не учтены в запросе итогов.

Решение: Проверьте соответствие условий в основном запросе и запросе детализации. Используйте ОБЪЕДИНИТЬ для совмещения данных.

⚠️ Внимание: В 1С:Предприятие 8.3.21+ появилась возможность использовать в запросах ПАРАМЕТРЫ СЕАНСА, что упрощает работу с динамическими фильтрами. Однако в более ранних версиях это может привести к ошибкам при изменении параметров.

FAQ: Ответы на частые вопросы

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

Используйте функцию ВЫРАЗИТЬ для приведения даты к нужному формату:

  • По дням: ВЫРАЗИТЬ(Дата КАК Дата)
  • По месяцам: ВЫРАЗИТЬ(Дата КАК Месяц)
  • По кварталам: ВЫРАЗИТЬ(Дата КАК Квартал)
  • По годам: ВЫРАЗИТЬ(Дата КАК Год)

Пример:

ВЫБРАТЬ

ВЫРАЗИТЬ(Документ.Дата КАК Месяц) КАК Месяц,

СУММА(Документ.Сумма) КАК ИтогПоМесяцу

ИЗ

Документ.РеализацияТоваровУслуг КАК Документ

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

ВЫРАЗИТЬ(Документ.Дата КАК Месяц)

Можно ли в одном запросе получить и детализацию, и итоги?

Да, для этого используйте конструкцию ОБЪЕДИНИТЬ с подзапросами:

ВЫБРАТЬ

"" КАК УровеньДетализации,

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

СУММА(Документ.Количество) КАК Количество

ИЗ

Документ.РеализацияТоваровУслуг КАК Документ

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура

ПО Документ.Номенклатура = Номенклатура.Ссылка

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

Номенклатура.Наименование

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ

"ИТОГО" КАК УровеньДетализации,

"" КАК Наименование,

СУММА(Документ.Количество) КАК Количество

ИЗ

Документ.РеализацияТоваровУслуг КАК Документ

В результате вы получите строки с детализацией по номенклатуре и одну строку с итогом.

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

Для этого нужно:

  1. Получить итоги по группам (как описано в разделе 1).
  2. Выгрузить результат в таблицу значений.
  3. Рассчитать общий итог и доли в цикле:
Результат = Запрос.Выполнить().Выгрузить();

ОбщийИтог = Результат.Итог("Сумма");

Для Каждого Строка Из Результат Цикл

Строка.Доля = Строка.Сумма / ОбщийИтог * 100;

КонецЦикла;