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

В этой статье разберем 5 практических способов группировки строк в 1С — от элементарных операций в консоли запросов до оптимизированных алгоритмов для обработки миллионов записей. Особое внимание уделим типичным ошибкам, которые тормозят систему, и покажем, как избежать "проклятия последней строки" (когда группировка игнорирует одну запись из-за неверного условия). Все примеры приведены для актуальных версий платформы 1С:Предприятие 8.3 и протестированы на реальных базах.

1. Группировка в запросах: оператор ГРУППИРОВКА ПО

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

Пример: сгруппируем документы РеализацияТоваровУслуг по контрагентам и посчитаем общую сумму продаж:

ВЫБРАТЬ

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

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

ИЗ

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

ГРУППИРОВКА ПО

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

  • 📌 Поля группировки — указываются после ГРУППИРОВКА ПО. Можно группировать по нескольким полям одновременно (например, по контрагенту и менеджеру).
  • 📊 Агрегатные функции — применяются к полям, не указанным в группировке. Поддерживаются СУММА, СРЕДНЕЕ, МИНИМУМ/МАКСИМУМ, КОЛИЧЕСТВО (включая КОЛИЧЕСТВО РАЗЛИЧНЫХ).
  • Производительность — группировка в запросе работает быстрее, чем программная обработка на клиенте, особенно для больших таблиц.
⚠️ Внимание: Если в выборке есть поле, не указанное ни в ГРУППИРОВКА ПО, ни в агрегатной функции, запрос вернет ошибку "Поле не входит ни в список выборки, ни в список группировки". Например, нельзя одновременно выводить РеализацияТоваровУслуг.Дата и суммировать по контрагенту без группировки по дате.
📊 Какой тип группировки вы используете чаще?
Запросы
Отчеты с компоновкой данных
Программный код (Циклы, Структуры)
СКД (Система компоновки данных)
Не использую

2. Иерархическая группировка: когда данных слишком много

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

Пример иерархического запроса для продаж по номенклатурным группам:

ВЫБРАТЬ

Номенклатура.Родитель КАК Группа,

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

СУММА(Продажи.Количество) КАК Количество

ИЗ

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

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

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

ГРУППИРОВКА ПО

Номенклатура.Родитель,

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

УПОРЯДОЧИТЬ ПО

Группа,

Товар

Для визуализации иерархии удобнее использовать СКД — она автоматически строит дерево группировок и позволяет разворачивать/сворачивать уровни. Настройка выполняется в конструкторе схемы компоновки данных:

  1. Добавьте поле группировки (например, Номенклатура.Родитель).
  2. Установите флаг "Иерархия" для этого поля.
  3. Настройте порядок группировок (сверху вниз: группа → подгруппа → элемент).

Убедитесь, что справочники имеют иерархическую структуру|Проверьте заполненность полей "Родитель"|Оцените объем данных (иерархия тормозит на >100к строк)|Настройте индексы для полей группировки-->

3. Группировка с условиями: фильтрация и ХАРАКТЕРИСТИКИ

Часто требуется сгруппировать данные не по всем записям, а только по тем, что удовлетворяют определенным условиям. Для этого используют:

  • 🔍 Условие ГДЕ — фильтрация до группировки (например, только продажи за текущий месяц).
  • 🎯 ХАРАКТЕРИСТИКИ — группировка по динамическим признакам (например, по диапазонам сумм: "до 1000", "1000-5000", "свыше 5000").

Пример запроса с характеристиками для анализа чеков по суммам:

ВЫБРАТЬ

ВЫРАЗИТЬ(КАК СТРОКА(50),

ВЫБОР

КОГДА Чеки.СуммаДокумента < 1000 ТОГДА "До 1000"

КОГДА Чеки.СуммаДокумента МЕЖДУ 1000 И 5000 ТОГДА "1000-5000"

ИНАЧЕ "Свыше 5000"

КОНЕЦ) КАК ДиапазонСуммы,

СУММА(Чеки.СуммаДокумента) КАК Итого

ИЗ

Документ.ЧекККМ КАК Чеки

ГРУППИРОВКА ПО

ДиапазонСуммы

Для сложных условий удобнее использовать временные таблицы:

// Сначала отбираем нужные данные

ВЫБРАТЬ

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

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

ПОМЕСТИТЬ ВТ_ОтфильтрованныеПродажи

ИЗ

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

ГДЕ

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

// Затем группируем

ВЫБРАТЬ

Отфильтрованные.Контрагент,

СУММА(Отфильтрованные.СуммаДокумента) КАК Итого

ИЗ

ВТ_ОтфильтрованныеПродажи КАК Отфильтрованные

ГРУППИРОВКА ПО

Отфильтрованные.Контрагент

⚠️ Внимание: При использовании ХАРАКТЕРИСТИК в больших запросах ( может создавать временные таблицы в памяти) следите за параметром MemoryLimit в файле конфигурации. Превышение лимита приводит к ошибке "Недостаточно памяти".

4. Программная группировка: когда запросы не помогают

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

  • 🔄 Циклы — перебор массива с ручной группировкой в Структуру или Соответствие.
  • 📊 Объект ТаблицаЗначений — группировка с помощью метода Свернуть().
  • 🛠 КоллекцииМассив, СписокЗначений или ДеревоЗначений для иерархических данных.

Пример группировки через Соответствие:

// Исходные данные - таблица с продажами

ТаблицаПродаж = Новый ТаблицаЗначений;

ТаблицаПродаж.Колонки.Добавить("Контрагент");

ТаблицаПродаж.Колонки.Добавить("Сумма");

// Заполняем данными (в реальности - из запроса или документа)

Для Каждого Строка Из ИсточникДанных Цикл

НоваяСтрока = ТаблицаПродаж.Добавить();

НоваяСтрока.Контрагент = Строка.Контрагент;

НоваяСтрока.Сумма = Строка.Сумма;

КонецЦикла;

// Группируем в Соответствие

Группы = Новый Соответствие;

Для Каждого Строка Из ТаблицаПродаж Цикл

Если НЕ Группы.СодержитКлюч(Строка.Контрагент) Тогда

Группы.Вставить(Строка.Контрагент, 0);

КонецЕсли;

Группы[Строка.Контрагент] = Группы[Строка.Контрагент] + Строка.Сумма;

КонецЦикла;

Для больших объемов данных (100 000+ строк) лучше использовать ТаблицаЗначений.Свернуть():

ТаблицаПродаж.Колонки.Добавить("ИтогоПоКонтрагенту");

ТаблицаПродаж.Свернуть("Контрагент", "Сумма", "ИтогоПоКонтрагенту");

Метод Плюсы Минусы Когда использовать
Соответствие Гибкость, поддержка сложной логики Медленнее на больших данных Динамическая обработка с условиями
ТаблицаЗначений.Свернуть() Быстро, оптимизировано платформой Ограниченные настройки группировки Простая сумма/количество по группам
ДеревоЗначений Поддержка иерархии Сложно в отладке Многоуровневые отчеты
💡

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

5. Группировка в отчетах: Система компоновки данных (СКД)

Система компоновки данных (СКД) — самый мощный инструмент для группировки в , так как позволяет:

  • 📈 Настраивать многоуровневые группировки (вложенность до 10 уровней).
  • 🎨 Визуализировать данные в виде диаграмм, сводных таблиц или деревьев.
  • 🔧 Добавлять вычисляемые поля и условное оформление.

Пошаговая инструкция настройки группировки в СКД:

  1. Откройте схему компоновки данных в конструкторе отчета.
  2. В разделе "Группировки" добавьте поле (например, Контрагент).
  3. Настройте порядок группировок перетаскиванием мышью.
  4. Для иерархии отметьте флаг "Иерархия" и укажите поле родителя.
  5. В разделе "Ресурсы" добавьте агрегатные функции (например, Сумма(СуммаДокумента)).

Пример настройки группировки по месяцам и контрагентам:

// В модуле отчета

СхемаКомпоновкиДанных = ПолучаемСхемуКомпоновкиДанных();

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

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

ГруппировкаМесяц = НастройкиКомпоновки.Группировки.Добавить();

ГруппировкаМесяц.Поле = Новый ПолеКомпоновкиДанных("Месяц");

ГруппировкаМесяц.Тип = ТипГруппировкиКомпоновкиДанных.Группировка;

// Добавляем вложенную группировку по контрагенту

ГруппировкаКонтрагент = НастройкиКомпоновки.Группировки.Добавить();

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

ГруппировкаКонтрагент.Родитель = ГруппировкаМесяц;

⚠️ Внимание: В СКД группировка по дате требует предварительной обработки. Например, для группировки по месяцам добавьте вычисляемое поле НачалоМесяца(Дата) в набор данных, а не группируйтесь напрямую по Дата.
Как ускорить отчет с группировкой в СКД?

1. Используйте индексированные поля для группировки (например, справочники с пометкой "Индексировать").

2. Ограничьте период данных на уровне запроса, а не в отчете.

3. Отключите ненужные ресурсы (например, если не нужен "Максимум", уберите его из схемы).

4. Для больших отчетов (>50к строк) используйте серверный режим компоновки (КомпоновщикМакета.ВыполнитьСерверныйМодуль = Истина).

6. Оптимизация группировки: индексы, кэш и серверные вычисления

Неправильная группировка может "подвесить" базу на часы. Чтобы избежать тормозов:

  • 🚀 Индексы — добавьте индексы на поля, по которым часто группируетесь (в конфигураторе: свойство Индексировать для реквизитов справочников).
  • 💾 Кэширование — используйте ПланОбмена или РегистрСведений для хранения предварительно сгруппированных данных.
  • 🖥 Серверные процедуры — переносите тяжелые группировки в серверные функции или фоновые задания.

Пример оптимизации запроса с группировкой:

// Плохо (группировка по неиндексированному полю)

ВЫБРАТЬ

Документ.Наименование КАК ТипДокумента, // Поле не проиндексировано

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

ИЗ

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

ГРУППИРОВКА ПО

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

// Хорошо (группировка по справочнику с индексом)

ВЫБРАТЬ

Документ.ВидДокумента КАК ТипДокумента, // Поле "ВидДокумента" - ссылка на справочник с индексом

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

ИЗ

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

ГРУППИРОВКА ПО

Документ.ВидДокумента

Для крайне больших баз (>1 млн записей) рассмотрите:

  • 📂 Разделение данных — группировка по периодам (например, отдельные отчеты за месяц).
  • ☁️ Внешние СУБД — перенос исторических данных в PostgreSQL или MS SQL с последующей группировкой там.
💡

Индексы ускоряют группировку в 10-100 раз, но замедляют запись данных. Не индексируйте поля, которые редко используются в группировках или фильтрах.

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

Ошибка 1: "Пропала одна строка"

Симптом: при группировке одна запись не попадает в результат, хотя должна. Причина — неверное условие в ГДЕ или СОЕДИНЕНИЕ. Например, ЛЕВОЕ СОЕДИНЕНИЕ может обрезать строки, если не учесть NULL-значения.

Решение: используйте ВЫБОР КОГДА ... ТОГДА для обработки пустых значений:

ВЫБРАТЬ

ВЫРАЗИТЬ(Документ.Контрагент КАК СТРОКА) КАК Контрагент, // Преобразуем в строку, чтобы NULL стал пустой строкой

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

ИЗ

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

ГРУППИРОВКА ПО

Контрагент

Ошибка 2: "Запрос выполняется вечно"

Симптом: группировка по неиндексированным полям или слишком детализированным группам (например, по секундам в дате).

Решение:

  • Упростите группировку (например, группируйте по дням, а не по секундам).
  • Добавьте индексы или используйте материализованные представления.

Ошибка 3: "Неверные итоги"

Симптом: суммы в группировке не сходятся с реальными данными. Причина — неучтенные NULL-значения в агрегатных функциях.

Решение: используйте ВЫРАЗИТЬ или ЗНАЧЕНИЕ для замены NULL на 0:

СУММА(ВЫРАЗИТЬ(Документ.Сумма КАК ЧИСЛО(15, 2))) КАК Итого // Заменяем NULL на 0.00
⚠️ Внимание: В версиях 1С:Предприятие 8.3.20+ изменилось поведение агрегатных функций с NULL. Теперь СУММА(NULL) возвращает NULL, а не 0. Это ломает старые отчеты! Проверьте логику на актуальной платформе.

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

Как сгруппировать данные по диапазонам (например, возрастные группы 18-25, 26-35 и т.д.)?

Используйте конструкцию ВЫБОР КОГДА ... ТОГДА в запросе:

ВЫБРАТЬ

ВЫРАЗИТЬ(КАК СТРОКА(20),

ВЫБОР

КОГДА Возраст МЕЖДУ 18 И 25 ТОГДА "18-25"

КОГДА Возраст МЕЖДУ 26 И 35 ТОГДА "26-35"

ИНАЧЕ "36+"

КОНЕЦ) КАК ВозрастнаяГруппа,

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

ИЗ

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

ГРУППИРОВКА ПО

ВозрастнаяГруппа

Для динамических диапазонов (например, по процентилям) используйте программную обработку с Массивом или Структурой.

Можно ли сгруппировать данные по первым буквам наименования (например, "А-Б", "В-Г")?

Да, с помощью функции ЛЕВ():

ВЫБРАТЬ

ВЫРАЗИТЬ(КАК СТРОКА(2),

ВЫБОР

КОГДА ЛЕВ(Номенклатура.Наименование, 1) МЕЖДУ "А" И "Б" ТОГДА "А-Б"

КОГДА ЛЕВ(Номенклатура.Наименование, 1) МЕЖДУ "В" И "Г" ТОГДА "В-Г"

ИНАЧЕ "Другие"

КОНЕЦ) КАК АлфавитнаяГруппа,

СУММА(Продажи.Количество) КАК Количество

ИЗ ...

ГРУППИРОВКА ПО

АлфавитнаяГруппа

Для кириллицы учитывайте регистр: приведите строку к верхнему регистру (ВРЕГ()).

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

Используйте функции работы с датами:

  • Для недель: НАЧАЛОНЕДЕЛИ(Дата) или НОМЕРНЕДЕЛИГОДА(Дата).
  • Для кварталов: НАЧАЛОКВАРТАЛА(Дата) или выражение ЦЕЛ(МЕСЯЦ(Дата) / 3) + 1.

Пример группировки по кварталам:

ВЫБРАТЬ

ЦЕЛ(МЕСЯЦ(Документ.Дата) / 3) + 1 КАК Квартал,

СУММА(Документ.Сумма) КАК И