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

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

Запрос 1С с группировкой и отбором: СГРУППИРОВАТЬ ПО и ГДЕ

Как в запросе 1С совместить ГДЕ и СГРУППИРОВАТЬ ПО: порядок секций, агрегатные функции, ИМЕЮЩИЕ, типовые ошибки и готовые примеры кода.

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

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

Ниже разобран синтаксис, порядок следования секций, примеры кода для типовых конфигураций, отличие ГДЕ от ИМЕЮЩИЕ и способы проверить корректность результата до переноса запроса в рабочий код.

Порядок секций в запросе и почему это важно

Конструктор запросов 1С не позволит расположить секции в произвольном порядке, но при ручном наборе текста легко ошибиться. Правильная последовательность: ВЫБРАТЬ → ИЗ → ГДЕ → СГРУППИРОВАТЬ ПО → ИМЕЮЩИЕ → УПОРЯДОЧИТЬ ПО → ИТОГИ ПО. Логика обработки совпадает с порядком написания: сначала отбираются строки, потом они группируются, затем группы фильтруются по агрегатам.

Из этого следуют два практических правила. Первое: любые условия на обычные поля (период, организация, склад, признак проведения) выгоднее помещать в ГДЕ — отбор до группировки сокращает объём обрабатываемых данных и ускоряет запрос. Второе: условия вида «сумма продаж больше 100000» физически невозможно записать в ГДЕ, потому что на момент отбора строк суммы ещё не посчитаны. Такие условия пишутся в ИМЕЮЩИЕ.

Базовый пример: отбор в ГДЕ и группировка

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

ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

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

КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Продажи.Регистратор) КАК КоличествоДокументов

ИЗ

РегистрНакопления.Продажи.Обороты(&НачПериода, &КонПериода, , ) КАК Продажи

ГДЕ

Продажи.Организация = &Организация

И Продажи.Склад = &Склад

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

Продажи.Контрагент

УПОРЯДОЧИТЬ ПО

СуммаПродаж УБЫВ

Обратите внимание на три момента. Поле Контрагент присутствует и в списке выборки, и в секции СГРУППИРОВАТЬ ПО — это обязательное требование: любое неагрегированное поле выборки должно входить в группировку. Псевдонимы (КАК СуммаПродаж) позволяют обращаться к полям результата по понятным именам в коде и в секции УПОРЯДОЧИТЬ ПО. Условия в ГДЕ объединяются оператором И, а для альтернатив используется ИЛИ со скобками.

Отбор по агрегатам: секция ИМЕЮЩИЕ

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

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

Продажи.Контрагент

ИМЕЮЩИЕ

СУММА(Продажи.СуммаОборот) > &МинимальнаяСумма

И КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Продажи.Регистратор) >= 3

В ИМЕЮЩИЕ допустимо ссылаться и на псевдонимы агрегатных полей выборки, если версия платформы это поддерживает, но надёжнее дублировать агрегатное выражение целиком — так запрос остаётся совместимым при переносе между конфигурациями и режимами совместимости.

ГДЕ или ИМЕЮЩИЕ

ГДЕ

Фильтрует исходные строки до группировки. Условия только на обычные поля. Ускоряет запрос, сокращая объём данных.

ИМЕЮЩИЕ

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

Группировка по нескольким полям и особые случаи

Группировать можно по любому числу полей — они перечисляются через запятую. Каждая комбинация значений образует отдельную строку результата. Например, группировка по контрагенту и месяцу даёт разрез «клиент × месяц», что удобно для динамики продаж.

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

Продажи.Контрагент,

НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)

Группировка по выражению

В СГРУППИРОВАТЬ ПО допустимы функции и выражения: НАЧАЛОПЕРИОДА для сворачивания по месяцам или неделям, ВЫБОР для категорий, ВЫРАЗИТЬ для приведения типов. То же выражение должно стоять и в списке выборки, иначе платформа выдаст ошибку о несоответствии полей группировке.

Группировка без агрегатов и РАЗЛИЧНЫЕ

Если нужно просто убрать дубли строк, есть два пути: СГРУППИРОВАТЬ ПО по всем полям выборки либо ВЫБРАТЬ РАЗЛИЧНЫЕ. Результат идентичен, но РАЗЛИЧНЫЕ короче и читается проще. СГРУППИРОВАТЬ ПО оправдано, когда позже планируется добавить агрегаты или ИМЕЮЩИЕ.

Типичные ошибки и как их диагностировать

Первая и самая частая ошибка — попытка написать условие на агрегат в ГДЕ: «ГДЕ СУММА(Сумма) > 1000». Конструктор запросов и компилятор отклонят такой текст. Переносите условие в ИМЕЮЩИЕ.

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

Третья ошибка — условие в ГДЕ по полю соединённой таблицы при ЛЕВОМ СОЕДИНЕНИИ. Такое условие фактически превращает левое соединение во внутреннее: строки с пустой правой частью отбрасываются. Если нужно сохранить все строки левой таблицы, условие переносится в параметры соединения (секция ПО) или оборачивается проверкой на NULL.

Типичные ошибки
01
Условие на СУММА в секции ГДЕ — запрос не компилируется; перенесите условие в ИМЕЮЩИЕ.
02
Поле выборки вне группировки и без агрегата — ошибка платформы; добавьте поле в СГРУППИРОВАТЬ ПО или оберните в МАКСИМУМ.
03
Отбор в ГДЕ по полю правой таблицы при ЛЕВОМ СОЕДИНЕНИИ — теряются строки с NULL; перенесите условие в секцию соединения.
04
Группировка по ссылке, а вывод по наименованию без агрегата — оберните наименование в МАКСИМУМ.
05
Отбор по периоду в ГДЕ вместо параметров виртуальной таблицы оборотов — заметное замедление на больших регистрах.

Производительность: что отдать виртуальной таблице

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

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

Проверка результата перед переносом в код

До переноса запроса в модуль выполните его в консоли запросов с реальными параметрами и сверьте итоги с эталоном. Практический приём: снять группировку и вывести детальные строки с теми же условиями ГДЕ, затем вручную просуммировать одну группу — так проверяется и отбор, и агрегация одновременно.

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

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

Число строк результата
Норма

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

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

Строк больше — значит, в группировку попало лишнее поле

Сумма по группе
Норма

Совпадает с суммой детальных строк той же группы при том же отборе

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

Расхождение — проверьте КОЛИЧЕСТВО vs СУММА, РАЗЛИЧНЫЕ и условия ГДЕ

Строки левой таблицы
Норма

Все ожидаемые строки присутствуют, пустые значения правой части — NULL

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

Часть строк пропала — условие в ГДЕ «съело» строки соединения

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

Итог

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

ГДЕ фильтрует строки до группировки и стоит перед СГРУППИРОВАТЬ ПО; отбор по агрегатам пишется в ИМЕЮЩИЕ. Каждое неагрегированное поле выборки должно входить в группировку. Отборы по виртуальным таблицам регистров выгоднее передавать параметрами, а результат проверять на копии базы сличением с детальными строками.

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

Можно ли использовать СГРУППИРОВАТЬ ПО без ГДЕ?

Да. Секция ГДЕ необязательна: если отбор не нужен, запрос начинается с ВЫБРАТЬ и ИЗ, а затем сразу идёт СГРУППИРОВАТЬ ПО. Группировка будет выполнена по всем строкам источника.

Чем ИМЕЮЩИЕ отличается от ГДЕ на практике?

ГДЕ работает с исходными строками до сворачивания и не может ссылаться на агрегатные функции. ИМЕЮЩИЕ работает с уже сформированными группами и предназначено именно для условий на СУММА, КОЛИЧЕСТВО и другие агрегаты. Одно и то же логическое условие, записанное в разных секциях, даст разный результат.

Почему запрос с группировкой возвращает больше строк, чем ожидалось?

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

Как сгруппировать по месяцам, если в таблице только дата?

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

Что выбрать: РАЗЛИЧНЫЕ или СГРУППИРОВАТЬ ПО для удаления дублей?

Для простого устранения дублей без вычислений достаточно ВЫБРАТЬ РАЗЛИЧНЫЕ — запрос короче и понятнее. СГРУППИРОВАТЬ ПО нужен, когда требуются агрегатные функции или последующий отбор групп через ИМЕЮЩИЕ.

Работает ли ИМЕЮЩИЕ без СГРУППИРОВАТЬ ПО?

Нет, секция ИМЕЮЩИЕ имеет смысл только вместе с группировкой — она фильтрует именно группы. Если группировки в запросе нет, агрегатные условия придётся реализовывать через вложенный запрос: сначала сгруппировать во вложенном, затем отобрать в ГДЕ внешнего запроса.