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