Разработка и Конфигурация · 12 мин
Как свернуть результат запроса в 1С
Как свернуть результат запроса в 1С: метод Свернуть() таблицы значений, группировка ГруппирующиеНаборы, итоги в запросе. Примеры кода, ошибки и проверка результата.
Под свёрткой результата запроса в 1С обычно понимают одно из двух действий: либо агрегирование строк прямо в тексте запроса через группировку и итоговые функции, либо свёртку уже полученной таблицы значений методом Свернуть(). Оба подхода решают одну задачу — убрать детальные строки и оставить только уникальные комбинации измерений с посчитанными суммами, — но различаются по месту выполнения и стоимости для системы.
Выбор способа влияет на производительность: группировка на стороне СУБД почти всегда быстрее, чем выгрузка полного результата в память сервера 1С с последующей свёрткой. Однако метод Свернуть() незаменим, когда таблица уже собрана из нескольких источников или получена не запросом, а, например, загружена из файла.
Ниже разобраны оба механизма, типовые ошибки (потеря строк из-за NULL, свёртка по лишним колонкам), способы проверить корректность итогов и критерии выбора между запросной группировкой и свёрткой таблицы значений.
Что значит «свернуть результат запроса» и когда это нужно
Свёртка — это преобразование набора строк, в котором строки с одинаковыми значениями ключевых колонок объединяются в одну, а числовые показатели суммируются (или агрегируются иначе). Например, результат запроса по продажам содержит строки «Товар — Документ — Количество», а нужна таблица «Товар — Суммарное количество» без детализации до документов.
Типовые ситуации, где требуется свёртка: подготовка данных для отчёта без лишней детализации, сравнение двух таблиц по итоговым значениям, расчёт остатков по измерениям верхнего уровня, подготовка таблицы для обмена или печатной формы, где детальные строки не нужны.
Важно понимать, что свёртка — операция необратимая: детальные строки после неё восстановить нельзя. Если детализация может понадобиться позже, исходную таблицу следует сохранить отдельно, а сворачивать копию.
Свёртка в тексте запроса через группировку
Самый эффективный способ — не выгружать детальные строки вовсе, а сразу написать запрос с группировкой. В языке запросов 1С для этого используется секция СГРУППИРОВАТЬ ПО и агрегатные функции СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ.
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
СУММА(Продажи.Количество) КАК Количество,
СУММА(Продажи.Сумма) КАК Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
Продажи.Номенклатура
Ключевое правило: все неагрегатные поля в списке выборки обязаны присутствовать в секции СГРУППИРОВАТЬ ПО. Если поле забыть, запрос либо не выполнится, либо (в режиме совместимости) даст неочевидный результат. Обратная ситуация допустима: группировать можно по полю, которое не выводится в выборку.
Для устранения дублей без суммирования (когда числовых полей нет или они не нужны) вместо группировки используют ключевое слово РАЗЛИЧНЫЕ. Это тоже форма свёртки: остаются только уникальные комбинации выбранных полей.
Свёртка таблицы значений методом Свернуть()
Если результат запроса уже выгружен в таблицу значений через Результат.Выгрузить(), его можно свернуть встроенным методом Свернуть(). Метод принимает два параметра: строку с именами колонок группировки и строку с именами суммируемых колонок (оба параметра — перечисления через запятую).
Запрос = Новый Запрос("ВЫБРАТЬ ... ИЗ РегистрНакопления.Продажи");
ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
// Свернуть копию, сохранив исходную детализацию
СвернутаяТаблица = ТаблицаРезультат.Скопировать();
СвернутаяТаблица.Свернуть("Номенклатура, Склад", "Количество, Сумма");
У метода есть несколько особенностей, о которых часто забывают. Во-первых, все колонки, не указанные ни в первом, ни во втором параметре, удаляются из таблицы без предупреждения. Во-вторых, суммируемые колонки должны иметь числовой тип — иначе при суммировании значений разных типов можно получить ошибку или непредсказуемый результат. В-третьих, метод изменяет саму таблицу, а не возвращает новую, поэтому для сохранения исходных данных нужна копия.
Если второй параметр не указать, метод просто удалит дубли строк по колонкам группировки — аналог РАЗЛИЧНЫЕ в запросе. Это удобно для получения уникальных комбинаций измерений.
- 1Выгрузите результат запроса: ТЗ = Запрос.Выполнить().Выгрузить()
- 2При необходимости создайте копию: ТЗСвертка = ТЗ.Скопировать()
- 3Определите колонки группировки — по ним строки будут объединяться
- 4Определите числовые колонки для суммирования
- 5Вызовите ТЗСвертка.Свернуть("КолонкиГрупп", "КолонкиСумм")
- 6Проверьте: сумма по свёрнутой таблице должна совпасть с суммой исходной
Сравнение подходов: запрос или таблица значений
Оба способа дают одинаковый логический результат, но различаются по ресурсоёмкости и области применения. Группировка в запросе выполняется на СУБД, по сети передаются только итоговые строки, а память сервера 1С не расходуется на детальные данные. Свёртка таблицы значений требует сначала получить все строки, что при больших объёмах даёт лишнюю нагрузку.
| Критерий | Группировка в запросе | Метод Свернуть() |
|---|---|---|
| Где выполняется | На стороне СУБД | На сервере 1С в памяти |
| Объём передаваемых данных | Только итоговые строки | Все детальные строки |
| Источник данных | Только данные, доступные запросу | Любая таблица значений, включая собранную из нескольких источников |
| Дополнительные агрегаты | СРЕДНЕЕ, МАКСИМУМ, МИНИМУМ, КОЛИЧЕСТВО(РАЗЛИЧНЫЕ) | Только сумма |
| Типичное применение | Отчёты, выборки итогов | Постобработка, объединённые данные, загрузка из файлов |
Практическое правило: если данные целиком берутся из одного запроса — сворачивайте в запросе. Метод Свернуть() оставьте для случаев, когда таблица собрана программно, объединяет несколько источников или получена извне.
Как выбрать способ свёртки
Типичные ошибки при свёртке и как их избежать
Самая частая ошибка — потеря колонок при вызове Свернуть(). Разработчик указывает только часть нужных колонок, и после свёртки обнаруживает, что, например, колонка «Склад» исчезла. Перед вызовом метода стоит явно выписать, какие колонки должны остаться в результате, и сверить со строкой параметров.
Вторая группа ошибок связана со значениями NULL. В запросе СУММА корректно игнорирует NULL, но группировка по полю, содержащему NULL, создаст отдельную строку с пустым значением. Если такие строки нежелательны, добавьте отбор НЕ Поле ЕСТЬ NULL или используйте ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) в группировке.
Третья типичная проблема — свёртка по ссылочным полям с разными представлениями. Строки считаются совпадающими только при равенстве значений колонок группировки; две разные ссылки на «один и тот же» по мнению пользователя элемент (например, дубли контрагентов) свёрнуты не будут. Вопрос дублей справочника решается до свёртки, на уровне данных.
Проверка корректности свёртки
Главный контрольный приём — сравнение итогов до и после свёртки. Сумма по каждой суммируемой колонке исходной таблицы должна совпадать с суммой свёрнутой таблицы. Для таблицы значений это делается через метод Итог("ИмяКолонки"), для запроса — через секцию ИТОГИ ОБЩИЕ или отдельный контрольный запрос.
СуммаДо = ТаблицаРезультат.Итог("Сумма");
СвернутаяТаблица = ТаблицаРезультат.Скопировать();
СвернутаяТаблица.Свернуть("Номенклатура", "Сумма");
СуммаПосле = СвернутаяТаблица.Итог("Сумма");
Если СуммаДо <> СуммаПосле Тогда
ВызватьИсключение "Свёртка исказила итоги";
КонецЕсли;
Дополнительно проверьте количество строк: в свёрнутой таблице не должно быть двух строк с одинаковой комбинацией колонок группировки. Простой способ — загрузить колонки группировки в соответствие или сверить число строк свёрнутой таблицы с числом строк результата запроса КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) по тем же полям.
Как проверить результат свёртки
Итоги совпадают
Итоги различаются — свёрнуты не все строки или потеряны данные
Каждая комбинация встречается один раз
Есть повторяющиеся комбинации — значения различаются по типу или скрытым символам
Остались только колонки группировки и сумм
Пропала нужная колонка — она не была указана в параметрах
Альтернативы: итоги в запросе и сводные представления
Не всегда свёртка нужна в явном виде. Если задача — показать итоги вместе с детализацией, используйте секцию ИТОГИ ПО в запросе и обход результата с группировкой: Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Так в одном запросе доступны и детальные строки, и подсчитанные на СУБД итоги по каждому уровню.
Для отчётов на СКД (система компоновки данных) свёртка вообще не требуется вручную: группировки и ресурсы настраиваются в схеме, а агрегацию выполняет компоновщик. Ручная свёртка в коде при использовании СКД — признак того, что механизм применён не по назначению.
Ещё одна альтернатива — временные таблицы: детальные данные помещаются во временную таблицу, а итоговый запрос группирует уже её. Это удобно, когда перед свёрткой нужно обогатить данные (подставить представления, рассчитать поля) на стороне СУБД, не выгружая строки в память.
Что важно запомнить
Сворачивайте данные как можно раньше — в идеале группировкой в тексте запроса на стороне СУБД. Метод Свернуть() применяйте к таблицам, собранным из нескольких источников, и всегда к копии исходной таблицы. После свёртки сверяйте итоги по суммируемым колонкам — это главный контроль корректности.
Частые вопросы
Чем Свернуть() отличается от РАЗЛИЧНЫЕ в запросе?
РАЗЛИЧНЫЕ убирает дубли строк на стороне СУБД ещё до передачи данных в 1С и не суммирует числовые поля. Свернуть() работает с уже выгруженной таблицей значений и умеет суммировать указанные колонки. Если нужны только уникальные строки без сумм, оба способа эквивалентны по результату, но РАЗЛИЧНЫЕ эффективнее.
Почему после Свернуть() пропали нужные колонки?
Метод удаляет все колонки, не перечисленные ни в параметре колонок группировки, ни в параметре суммируемых колонок. Это штатное поведение. Чтобы колонка сохранилась, добавьте её в первый параметр — тогда строки будут группироваться и по ней.
Можно ли при свёртке посчитать среднее или максимум?
Метод Свернуть() умеет только суммировать. Для среднего, максимума, минимума или количества различных значений используйте группировку в запросе с функциями СРЕДНЕЕ, МАКСИМУМ, МИНИМУМ, КОЛИЧЕСТВО(РАЗЛИЧНЫЕ). Если данные уже в таблице значений, агрегаты придётся считать вручную в цикле.
Как свернуть таблицу по части колонок, сохранив остальные?
Напрямую нельзя: свёртка требует, чтобы каждая оставшаяся колонка была либо колонкой группировки, либо суммируемой. Если значение колонки одинаково внутри группы (например, ставка НДС у номенклатуры), включите её в колонки группировки — лишних строк это не создаст. Если значения различаются, решите, какое из них нужно, и получите его отдельным запросом или обработкой.
Почему строки с одинаковыми на вид значениями не сворачиваются?
Обычно причина в скрытых различиях: лишние пробелы или неразрывные пробелы в строках, разные ссылки при одинаковом представлении, различие типов значения (число и строка). Проверьте значения через СокрЛП, сравнение ссылок по уникальному идентификатору и типы колонок таблицы.
Что быстрее: группировка в запросе или Свернуть()?
Группировка в запросе практически всегда быстрее: агрегация выполняется на СУБД, а по сети и в память сервера 1С попадают только итоговые строки. Свернуть() вынуждает сначала выгрузить все детальные строки, что на больших объёмах даёт заметный расход памяти и времени.