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

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

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

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

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

Выбор способа влияет на производительность: группировка на стороне СУБД почти всегда быстрее, чем выгрузка полного результата в память сервера 1С с последующей свёрткой. Однако метод Свернуть() незаменим, когда таблица уже собрана из нескольких источников или получена не запросом, а, например, загружена из файла.

Ниже разобраны оба механизма, типовые ошибки (потеря строк из-за NULL, свёртка по лишним колонкам), способы проверить корректность итогов и критерии выбора между запросной группировкой и свёрткой таблицы значений.

Что значит «свернуть результат запроса» и когда это нужно

Свёртка — это преобразование набора строк, в котором строки с одинаковыми значениями ключевых колонок объединяются в одну, а числовые показатели суммируются (или агрегируются иначе). Например, результат запроса по продажам содержит строки «Товар — Документ — Количество», а нужна таблица «Товар — Суммарное количество» без детализации до документов.

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

Важно понимать, что свёртка — операция необратимая: детальные строки после неё восстановить нельзя. Если детализация может понадобиться позже, исходную таблицу следует сохранить отдельно, а сворачивать копию.

Свёртка в тексте запроса через группировку

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

ВЫБРАТЬ

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

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

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

ИЗ

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

ГДЕ

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

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

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

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

Для устранения дублей без суммирования (когда числовых полей нет или они не нужны) вместо группировки используют ключевое слово РАЗЛИЧНЫЕ. Это тоже форма свёртки: остаются только уникальные комбинации выбранных полей.

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

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

Запрос = Новый Запрос("ВЫБРАТЬ ... ИЗ РегистрНакопления.Продажи");

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

// Свернуть копию, сохранив исходную детализацию

СвернутаяТаблица = ТаблицаРезультат.Скопировать();

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

У метода есть несколько особенностей, о которых часто забывают. Во-первых, все колонки, не указанные ни в первом, ни во втором параметре, удаляются из таблицы без предупреждения. Во-вторых, суммируемые колонки должны иметь числовой тип — иначе при суммировании значений разных типов можно получить ошибку или непредсказуемый результат. В-третьих, метод изменяет саму таблицу, а не возвращает новую, поэтому для сохранения исходных данных нужна копия.

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

Порядок свёртки таблицы значений
  1. 1
    Выгрузите результат запроса: ТЗ = Запрос.Выполнить().Выгрузить()
  2. 2
    При необходимости создайте копию: ТЗСвертка = ТЗ.Скопировать()
  3. 3
    Определите колонки группировки — по ним строки будут объединяться
  4. 4
    Определите числовые колонки для суммирования
  5. 5
    Вызовите ТЗСвертка.Свернуть("КолонкиГрупп", "КолонкиСумм")
  6. 6
    Проверьте: сумма по свёрнутой таблице должна совпасть с суммой исходной

Сравнение подходов: запрос или таблица значений

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

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

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

Маршрут решения

Как выбрать способ свёртки

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

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

Самая частая ошибка — потеря колонок при вызове Свернуть(). Разработчик указывает только часть нужных колонок, и после свёртки обнаруживает, что, например, колонка «Склад» исчезла. Перед вызовом метода стоит явно выписать, какие колонки должны остаться в результате, и сверить со строкой параметров.

Вторая группа ошибок связана со значениями NULL. В запросе СУММА корректно игнорирует NULL, но группировка по полю, содержащему NULL, создаст отдельную строку с пустым значением. Если такие строки нежелательны, добавьте отбор НЕ Поле ЕСТЬ NULL или используйте ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) в группировке.

Третья типичная проблема — свёртка по ссылочным полям с разными представлениями. Строки считаются совпадающими только при равенстве значений колонок группировки; две разные ссылки на «один и тот же» по мнению пользователя элемент (например, дубли контрагентов) свёрнуты не будут. Вопрос дублей справочника решается до свёртки, на уровне данных.

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

Проверка корректности свёртки

Главный контрольный приём — сравнение итогов до и после свёртки. Сумма по каждой суммируемой колонке исходной таблицы должна совпадать с суммой свёрнутой таблицы. Для таблицы значений это делается через метод Итог("ИмяКолонки"), для запроса — через секцию ИТОГИ ОБЩИЕ или отдельный контрольный запрос.

СуммаДо = ТаблицаРезультат.Итог("Сумма");

СвернутаяТаблица = ТаблицаРезультат.Скопировать();

СвернутаяТаблица.Свернуть("Номенклатура", "Сумма");

СуммаПосле = СвернутаяТаблица.Итог("Сумма");

Если СуммаДо <> СуммаПосле Тогда

ВызватьИсключение "Свёртка исказила итоги";

КонецЕсли;

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

Контрольные точки

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

Итог по суммируемой колонке до и после свёртки
Норма

Итоги совпадают

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

Итоги различаются — свёрнуты не все строки или потеряны данные

Дубликаты по колонкам группировки
Норма

Каждая комбинация встречается один раз

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

Есть повторяющиеся комбинации — значения различаются по типу или скрытым символам

Состав колонок результата
Норма

Остались только колонки группировки и сумм

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

Пропала нужная колонка — она не была указана в параметрах

Альтернативы: итоги в запросе и сводные представления

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

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

Ещё одна альтернатива — временные таблицы: детальные данные помещаются во временную таблицу, а итоговый запрос группирует уже её. Это удобно, когда перед свёрткой нужно обогатить данные (подставить представления, рассчитать поля) на стороне СУБД, не выгружая строки в память.

Итог

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

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

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

Чем Свернуть() отличается от РАЗЛИЧНЫЕ в запросе?

РАЗЛИЧНЫЕ убирает дубли строк на стороне СУБД ещё до передачи данных в 1С и не суммирует числовые поля. Свернуть() работает с уже выгруженной таблицей значений и умеет суммировать указанные колонки. Если нужны только уникальные строки без сумм, оба способа эквивалентны по результату, но РАЗЛИЧНЫЕ эффективнее.

Почему после Свернуть() пропали нужные колонки?

Метод удаляет все колонки, не перечисленные ни в параметре колонок группировки, ни в параметре суммируемых колонок. Это штатное поведение. Чтобы колонка сохранилась, добавьте её в первый параметр — тогда строки будут группироваться и по ней.

Можно ли при свёртке посчитать среднее или максимум?

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

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

Напрямую нельзя: свёртка требует, чтобы каждая оставшаяся колонка была либо колонкой группировки, либо суммируемой. Если значение колонки одинаково внутри группы (например, ставка НДС у номенклатуры), включите её в колонки группировки — лишних строк это не создаст. Если значения различаются, решите, какое из них нужно, и получите его отдельным запросом или обработкой.

Почему строки с одинаковыми на вид значениями не сворачиваются?

Обычно причина в скрытых различиях: лишние пробелы или неразрывные пробелы в строках, разные ссылки при одинаковом представлении, различие типов значения (число и строка). Проверьте значения через СокрЛП, сравнение ссылок по уникальному идентификатору и типы колонок таблицы.

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

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