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

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

Как свернуть данные в запросе 1С

Как свернуть данные в запросе 1С: СГРУППИРОВАТЬ ПО, агрегатные функции, свертка таблицы значений методом Свернуть(). Примеры кода, ошибки и проверка результата.

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

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

Выбор между группировкой в запросе и сверткой таблицы значений влияет на производительность и объем передаваемых данных. Группировка на стороне СУБД почти всегда предпочтительнее, потому что сервер возвращает уже агрегированные строки. Свертка таблицы значений оправдана, когда данные уже получены и нужна дополнительная агрегация в коде.

Что значит «свернуть» в контексте запроса 1С

Свертка — это преобразование детальных строк в итоговые. Например, регистр продаж содержит строки «Товар А, документ 1, количество 2» и «Товар А, документ 2, количество 3». После свертки по товару остается одна строка: «Товар А, количество 5». Поля, по которым объединяются строки, называются полями группировки (измерениями), а поля, по которым вычисляются итоги, — ресурсами.

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

Группировка через СГРУППИРОВАТЬ ПО

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

ВЫБРАТЬ

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

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

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

ИЗ

РегистрНакопления.Продажи КАК Продажи

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

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

Доступные агрегатные функции: СУММА — итог по числовому полю; КОЛИЧЕСТВО — число строк (с РАЗЛИЧНЫЕ — число уникальных значений); МАКСИМУМ и МИНИМУМ — крайние значения; СРЕДНЕЕ — среднее арифметическое. Функции можно комбинировать в одном запросе для разных полей.

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

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

Нюансы группировки: NULL, итоги и виртуальные таблицы

При группировке по ссылочным полям помните про NULL: если поле может быть не заполнено, строки с пустым значением попадут в отдельную группу. Чтобы не потерять такие данные, используйте ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) и в выборке, и в секции группировки — выражения должны совпадать.

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

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

Свертка таблицы значений методом Свернуть()

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

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

ТЗ.Свернуть("Номенклатура, Склад", "Количество, Сумма");

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

Второй параметр можно опустить — тогда метод просто удалит дубли строк по полям группировки без суммирования. Это быстрый способ получить уникальные комбинации значений, аналог РАЗЛИЧНЫЕ в запросе.

Что выбрать: группировку в запросе или Свернуть() в коде

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

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

Сравнение вариантов

СГРУППИРОВАТЬ ПО в запросе

Подходит для больших объемов: агрегация на стороне СУБД, по сети идут только итоги. Ограничение — нельзя досвернуть результат по другим полям без нового запроса.

Свернуть() таблицы значений

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

Виртуальные таблицы регистров

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

Проверка результата и типичные ошибки

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

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

Вторая распространенная проблема — задвоение сумм из-за соединений. Если перед группировкой таблица соединяется с другой по условию «один ко многим», строки дублируются, и СУММА завышается кратно числу дублей. Признак — итоги ровно в 2, 3 и более раз больше ожидаемых. Решение: группировать каждую таблицу отдельно во временных таблицах и соединять уже свернутые результаты.

Типичные ошибки
01
Поле в выборке без агрегатной функции и вне группировки — запрос падает с ошибкой «Поле не входит в группу».
02
Соединение «один ко многим» до группировки — суммы задваиваются и завышаются кратно числу дублей.
03
Игнорирование NULL в полях группировки — строки с пустыми значениями попадают в отдельную группу или теряются при соединении.
04
Свернуть() без копии таблицы — удаляются нужные дальше колонки, код ниже падает с ошибкой обращения к колонке.
05
Группировка физической таблицы регистра вместо виртуальной — лишняя нагрузка на СУБД при больших объемах.
Контрольные точки

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

Контрольная сумма
Норма

Сумма по свернутой таблице равна сумме по исходной

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

Итог отличается — ищите NULL в группировке или задвоение из-за соединений

Число строк
Норма

Количество строк равно числу уникальных комбинаций полей группировки

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

Строк больше — группировка не сработала, проверьте расхождения в типах или представлениях полей

Состав колонок после Свернуть()
Норма

Остались только поля группировки и суммируемые поля

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

Код ниже обращается к удаленной колонке — нужна копия таблицы перед сверткой

Практический порядок действий

Типовой сценарий свертки данных из регистра в отчет выглядит так: определите измерения (по чему группируем), ресурсы (что суммируем) и период. Затем решите, где агрегировать — в запросе или в коде, — и проверьте результат контрольной суммой.

Порядок действий
  1. 1
    Определите поля группировки (измерения) и суммируемые поля (ресурсы).
  2. 2
    Проверьте, решает ли задачу виртуальная таблица регистра (Обороты, ОстаткиИОбороты) — если да, используйте ее.
  3. 3
    Напишите запрос с СГРУППИРОВАТЬ ПО и агрегатными функциями; обработайте NULL через ЕСТЬNULL.
  4. 4
    Если сворачиваете в коде — сделайте копию таблицы и вызовите Свернуть("Поля", "Суммы").
  5. 5
    Сверьте итоговую сумму с исходными данными и проверьте число строк результата.

Частые вопросы

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

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

Как свернуть и посчитать количество уникальных значений?

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

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

Да. Вызовите Свернуть с одним параметром — списком полей группировки: ТЗ.Свернуть("Номенклатура"). Метод удалит дубли и оставит по одной строке на каждое уникальное значение. Это аналог запроса с РАЗЛИЧНЫЕ.

Почему после группировки суммы стали больше, чем в исходных данных?

Почти всегда причина в соединении таблиц до группировки по условию «один ко многим»: строки основной таблицы продублировались, и СУММА посчитала их многократно. Разнесите агрегацию и соединение: сгруппируйте каждую таблицу во временной таблице, а затем соединяйте уже свернутые результаты.

Что быстрее: группировка запросом или Свернуть() в коде?

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

Итог

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

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