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

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

ИМЕЮЩИЕ и ГДЕ в запросах 1С: в чём разница и как применять

Чем отличаются ИМЕЮЩИЕ и ГДЕ в языке запросов 1С, когда применять каждый оператор, примеры кода, типичные ошибки и влияние на производительность.

Операторы ГДЕ и ИМЕЮЩИЕ в языке запросов 1С оба фильтруют данные, но работают на разных этапах выполнения запроса. ГДЕ отбирает строки до группировки, а ИМЕЮЩИЕ — уже сгруппированные итоги. Путаница между ними — одна из самых частых причин ошибок «Поле не найдено» и неожиданно медленных запросов у начинающих разработчиков.

Понимание разницы важно не только для синтаксиса: неправильно размещённое условие способно в разы увеличить объём обрабатываемых данных. Условие в ГДЕ отсекает лишние записи ещё на уровне таблицы, а условие в ИМЕЮЩИЕ вынуждает СУБД сначала сгруппировать всё, и только потом отбросить ненужное.

Ниже разобран синтаксис обоих операторов, порядок выполнения запроса, типовые сценарии, ошибки и способы проверить корректность результата.

Как работает оператор ГДЕ

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

ВЫБРАТЬ

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

Продажи.Количество

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Продажи

ГДЕ

Продажи.Ссылка.Дата >= &ДатаНачала

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

Ключевая особенность: чем раньше отсечены лишние строки, тем меньше данных идёт в соединения и группировку. Поэтому условия по датам, организациям, складам и другим измерениям всегда стоит размещать в ГДЕ, а не в ИМЕЮЩИЕ.

Как работает оператор ИМЕЮЩИЕ

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

ВЫБРАТЬ

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

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

ИЗ

Документ.РеализацияТоваровУслуг КАК Продажи

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

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

ИМЕЮЩИЕ

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

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

Порядок выполнения запроса: где срабатывает каждый фильтр

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

Порядок выполнения запроса
  1. 1
    ИЗ и соединения: формируется рабочий набор строк
  2. 2
    ГДЕ: отбрасываются строки, не подходящие под условие
  3. 3
    СГРУППИРОВАТЬ ПО: строки сворачиваются в группы, считаются агрегаты
  4. 4
    ИМЕЮЩИЕ: отбрасываются группы, не прошедшие условие по агрегатам
  5. 5
    ВЫБРАТЬ, УПОРЯДОЧИТЬ ПО, ИТОГИ: формируется итоговая выборка

Из этого порядка следует практический вывод: условие «Сумма > 100000» физически нельзя записать в ГДЕ, потому что на момент его применения суммы ещё не посчитаны. И наоборот, условие по дате документа в ИМЕЮЩИЕ заставит платформу группировать лишние строки, которые могли быть отсечены заранее.

Типовые сценарии: что выбрать

Фильтр по реквизитам — только ГДЕ

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

Фильтр по итогам — только ИМЕЮЩИЕ

Отобрать клиентов с суммой покупок выше порога, найти дубли (КОЛИЧЕСТВО > 1), исключить группы с нулевым остатком — такие задачи решаются только через ИМЕЮЩИЕ, потому что условие зависит от результата агрегации.

Комбинирование обоих операторов

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

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

ГДЕ

Фильтр строк до группировки. Быстро, но нельзя использовать агрегатные функции.

ИМЕЮЩИЕ

Фильтр групп после агрегации. Единственный способ отобрать по СУММА/КОЛИЧЕСТВО, но обрабатывает больше данных.

Параметры виртуальной таблицы

Самый ранний отбор для регистров. Предпочтительнее ГДЕ, но применим только к виртуальным таблицам.

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

Типичные ошибки
01
Агрегат в ГДЕ: запись 'ГДЕ СУММА(Сумма) > 0' вызывает ошибку компиляции запроса — переносите условие в ИМЕЮЩИЕ
02
Условие по дате в ИМЕЮЩИЕ: платформа группирует весь регистр за всё время, запрос работает в разы медленнее — переносите в ГДЕ или параметры виртуальной таблицы
03
ИМЕЮЩИЕ без группировки при детальных строках: результат неожиданно пустой или из одной строки — проверьте, действительно ли нужна агрегация
04
Условие по неагрегированному полю в ИМЕЮЩИЕ: поле должно входить в список группировки, иначе ошибка 'Неверные параметры в операции сравнения' или 'Поле не найдено'

Ещё одна распространённая проблема — условие на поле соединения, которое из-за ЛЕВОГО СОЕДИНЕНИЯ содержит NULL. В ГДЕ сравнение с NULL всегда даёт ложь, и строки молча выпадают из результата. Используйте ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) или явную проверку «Поле ЕСТЬ NULL».

Производительность: почему место условия имеет значение

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

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

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

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

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

Количество строк результата
Норма

Соответствует ручной выборке на малом периоде

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

Строк меньше, чем ожидалось — возможно, условие в ИМЕЮЩИЕ отсекло нужные группы или NULL в ГДЕ

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

Итог по выборке сходится с отчётом по регистру за тот же период

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

Расхождения — проверьте, не потеряны ли строки из-за внутреннего соединения или условия ГДЕ

Время выполнения
Норма

Запрос отрабатывает за секунды на типовом периоде

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

Минуты — условия по измерениям, скорее всего, стоят в ИМЕЮЩИЕ вместо ГДЕ

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

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

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

Да. В этом случае весь результат считается одной группой, и условие применяется к агрегатам по всей выборке. Но если в секции ВЫБРАТЬ есть неагрегатные поля, запрос не выполнится — их нужно либо убрать, либо добавить группировку.

Почему запрос с ГДЕ по СУММА выдаёт ошибку?

Агрегатные функции запрещены в ГДЕ, потому что этот оператор выполняется до группировки, когда агрегаты ещё не вычислены. Перенесите условие в секцию ИМЕЮЩИЕ — это и есть его назначение.

Что быстрее: ИМЕЮЩИЕ или вложенный запрос с ГДЕ?

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

Работает ли ИМЕЮЩИЕ с псевдонимами полей?

Да, в условии можно ссылаться на псевдоним агрегатного поля, объявленный в ВЫБРАТЬ, например: ИМЕЮЩИЕ СуммаПродаж > 100000. Это сокращает текст и снижает риск ошибки при изменении выражения агрегата.

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

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

Влияет ли ИТОГИ на работу ИМЕЮЩИЕ?

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

Итог

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

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