Работа с большими массивами данных в 1С:Предприятие часто требует объединения строк по общим признакам — будь то аналитика продаж по категориям, сводка остатков по складам или консолидация документов по контрагентам. Без правильной группировки отчеты превращаются в бесконечные таблицы, а аналитика теряет смысл. Однако даже опытные пользователи не всегда знают, как эффективно сгруппировать данные: через запросы, отчеты, компоновку данных или программный код.
В этой статье разберем 5 практических способов группировки строк в 1С — от элементарных операций в консоли запросов до оптимизированных алгоритмов для обработки миллионов записей. Особое внимание уделим типичным ошибкам, которые тормозят систему, и покажем, как избежать "проклятия последней строки" (когда группировка игнорирует одну запись из-за неверного условия). Все примеры приведены для актуальных версий платформы 1С:Предприятие 8.3 и протестированы на реальных базах.
1. Группировка в запросах: оператор ГРУППИРОВКА ПО
Базовый метод объединения строк — использование конструкции ГРУППИРОВКА ПО в языке запросов. Он позволяет свести тысячи записей к нескольким строкам по заданным полям, при этом поддерживает агрегатные функции вроде СУММА(), КОЛИЧЕСТВО() или МАКСИМУМ().
Пример: сгруппируем документы РеализацияТоваровУслуг по контрагентам и посчитаем общую сумму продаж:
ВЫБРАТЬ
РеализацияТоваровУслуг.Контрагент КАК Контрагент,
СУММА(РеализацияТоваровУслуг.СуммаДокумента) КАК ИтогоПродаж
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГРУППИРОВКА ПО
РеализацияТоваровУслуг.Контрагент
- 📌 Поля группировки — указываются после
ГРУППИРОВКА ПО. Можно группировать по нескольким полям одновременно (например, по контрагенту и менеджеру). - 📊 Агрегатные функции — применяются к полям, не указанным в группировке. Поддерживаются
СУММА,СРЕДНЕЕ,МИНИМУМ/МАКСИМУМ,КОЛИЧЕСТВО(включаяКОЛИЧЕСТВО РАЗЛИЧНЫХ). - ⚡ Производительность — группировка в запросе работает быстрее, чем программная обработка на клиенте, особенно для больших таблиц.
⚠️ Внимание: Если в выборке есть поле, не указанное ни вГРУППИРОВКА ПО, ни в агрегатной функции, запрос вернет ошибку "Поле не входит ни в список выборки, ни в список группировки". Например, нельзя одновременно выводитьРеализацияТоваровУслуг.Датаи суммировать по контрагенту без группировки по дате.
2. Иерархическая группировка: когда данных слишком много
Для многоуровневой аналитики (например, продажи по регионам → городам → магазинам) применяют иерархическую группировку. В 1С это реализуется либо через вложенные запросы, либо с помощью СКД (Системы компоновки данных).
Пример иерархического запроса для продаж по номенклатурным группам:
ВЫБРАТЬ
Номенклатура.Родитель КАК Группа,
Номенклатура.Наименование КАК Товар,
СУММА(Продажи.Количество) КАК Количество
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
ПО Продажи.Номенклатура = Номенклатура.Ссылка
ГРУППИРОВКА ПО
Номенклатура.Родитель,
Номенклатура.Наименование
УПОРЯДОЧИТЬ ПО
Группа,
Товар
Для визуализации иерархии удобнее использовать СКД — она автоматически строит дерево группировок и позволяет разворачивать/сворачивать уровни. Настройка выполняется в конструкторе схемы компоновки данных:
- Добавьте поле группировки (например,
Номенклатура.Родитель). - Установите флаг "Иерархия" для этого поля.
- Настройте порядок группировок (сверху вниз: группа → подгруппа → элемент).
Убедитесь, что справочники имеют иерархическую структуру|Проверьте заполненность полей "Родитель"|Оцените объем данных (иерархия тормозит на >100к строк)|Настройте индексы для полей группировки-->
3. Группировка с условиями: фильтрация и ХАРАКТЕРИСТИКИ
Часто требуется сгруппировать данные не по всем записям, а только по тем, что удовлетворяют определенным условиям. Для этого используют:
- 🔍 Условие
ГДЕ— фильтрация до группировки (например, только продажи за текущий месяц). - 🎯
ХАРАКТЕРИСТИКИ— группировка по динамическим признакам (например, по диапазонам сумм: "до 1000", "1000-5000", "свыше 5000").
Пример запроса с характеристиками для анализа чеков по суммам:
ВЫБРАТЬ
ВЫРАЗИТЬ(КАК СТРОКА(50),
ВЫБОР
КОГДА Чеки.СуммаДокумента < 1000 ТОГДА "До 1000"
КОГДА Чеки.СуммаДокумента МЕЖДУ 1000 И 5000 ТОГДА "1000-5000"
ИНАЧЕ "Свыше 5000"
КОНЕЦ) КАК ДиапазонСуммы,
СУММА(Чеки.СуммаДокумента) КАК Итого
ИЗ
Документ.ЧекККМ КАК Чеки
ГРУППИРОВКА ПО
ДиапазонСуммы
Для сложных условий удобнее использовать временные таблицы:
// Сначала отбираем нужные данные
ВЫБРАТЬ
Продажи.Контрагент,
Продажи.СуммаДокумента
ПОМЕСТИТЬ ВТ_ОтфильтрованныеПродажи
ИЗ
Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода
// Затем группируем
ВЫБРАТЬ
Отфильтрованные.Контрагент,
СУММА(Отфильтрованные.СуммаДокумента) КАК Итого
ИЗ
ВТ_ОтфильтрованныеПродажи КАК Отфильтрованные
ГРУППИРОВКА ПО
Отфильтрованные.Контрагент
⚠️ Внимание: При использованииХАРАКТЕРИСТИКв больших запросах (1С может создавать временные таблицы в памяти) следите за параметромMemoryLimitв файле конфигурации. Превышение лимита приводит к ошибке "Недостаточно памяти".
4. Программная группировка: когда запросы не помогают
Если данные нужно обработать динамически (например, с дополнительной логикой, которую нельзя выразить в запросе), используют программные методы:
- 🔄 Циклы — перебор массива с ручной группировкой в
СтруктуруилиСоответствие. - 📊 Объект
ТаблицаЗначений— группировка с помощью методаСвернуть(). - 🛠 Коллекции —
Массив,СписокЗначенийилиДеревоЗначенийдля иерархических данных.
Пример группировки через Соответствие:
// Исходные данные - таблица с продажами
ТаблицаПродаж = Новый ТаблицаЗначений;
ТаблицаПродаж.Колонки.Добавить("Контрагент");
ТаблицаПродаж.Колонки.Добавить("Сумма");
// Заполняем данными (в реальности - из запроса или документа)
Для Каждого Строка Из ИсточникДанных Цикл
НоваяСтрока = ТаблицаПродаж.Добавить();
НоваяСтрока.Контрагент = Строка.Контрагент;
НоваяСтрока.Сумма = Строка.Сумма;
КонецЦикла;
// Группируем в Соответствие
Группы = Новый Соответствие;
Для Каждого Строка Из ТаблицаПродаж Цикл
Если НЕ Группы.СодержитКлюч(Строка.Контрагент) Тогда
Группы.Вставить(Строка.Контрагент, 0);
КонецЕсли;
Группы[Строка.Контрагент] = Группы[Строка.Контрагент] + Строка.Сумма;
КонецЦикла;
Для больших объемов данных (100 000+ строк) лучше использовать ТаблицаЗначений.Свернуть():
ТаблицаПродаж.Колонки.Добавить("ИтогоПоКонтрагенту");
ТаблицаПродаж.Свернуть("Контрагент", "Сумма", "ИтогоПоКонтрагенту");
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
Соответствие |
Гибкость, поддержка сложной логики | Медленнее на больших данных | Динамическая обработка с условиями |
ТаблицаЗначений.Свернуть() |
Быстро, оптимизировано платформой | Ограниченные настройки группировки | Простая сумма/количество по группам |
ДеревоЗначений |
Поддержка иерархии | Сложно в отладке | Многоуровневые отчеты |
Если группируете данные в цикле, используйте Прервать или Продолжить для оптимизации. Например, пропускайте строки с нулевыми суммами, чтобы ускорить обработку.
5. Группировка в отчетах: Система компоновки данных (СКД)
Система компоновки данных (СКД) — самый мощный инструмент для группировки в 1С, так как позволяет:
- 📈 Настраивать многоуровневые группировки (вложенность до 10 уровней).
- 🎨 Визуализировать данные в виде диаграмм, сводных таблиц или деревьев.
- 🔧 Добавлять вычисляемые поля и условное оформление.
Пошаговая инструкция настройки группировки в СКД:
- Откройте схему компоновки данных в конструкторе отчета.
- В разделе "Группировки" добавьте поле (например,
Контрагент). - Настройте порядок группировок перетаскиванием мышью.
- Для иерархии отметьте флаг "Иерархия" и укажите поле родителя.
- В разделе "Ресурсы" добавьте агрегатные функции (например,
Сумма(СуммаДокумента)).
Пример настройки группировки по месяцам и контрагентам:
// В модуле отчета
СхемаКомпоновкиДанных = ПолучаемСхемуКомпоновкиДанных();
НастройкиКомпоновки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
// Добавляем группировку по месяцу
ГруппировкаМесяц = НастройкиКомпоновки.Группировки.Добавить();
ГруппировкаМесяц.Поле = Новый ПолеКомпоновкиДанных("Месяц");
ГруппировкаМесяц.Тип = ТипГруппировкиКомпоновкиДанных.Группировка;
// Добавляем вложенную группировку по контрагенту
ГруппировкаКонтрагент = НастройкиКомпоновки.Группировки.Добавить();
ГруппировкаКонтрагент.Поле = Новый ПолеКомпоновкиДанных("Контрагент");
ГруппировкаКонтрагент.Родитель = ГруппировкаМесяц;
⚠️ Внимание: В СКД группировка по дате требует предварительной обработки. Например, для группировки по месяцам добавьте вычисляемое полеНачалоМесяца(Дата)в набор данных, а не группируйтесь напрямую поДата.
Как ускорить отчет с группировкой в СКД?
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 КАК Квартал,
СУММА(Документ.Сумма) КАК И