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

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

Чем отличается ГДЕ от ИМЕЮЩИЕ в запросах 1С

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

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

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

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

Что делает оператор ГДЕ

ГДЕ — это условие отбора строк источника данных. Оно применяется к каждой записи таблицы (или виртуальной таблицы) ещё до того, как выполняется группировка и вычисляются итоги. В условии можно использовать поля таблиц, параметры, операции сравнения, ПОДОБНО, В, МЕЖДУ, проверку на NULL и логические связки И/ИЛИ.

Типичный пример — отбор оборотов по конкретной организации и периоду:

Выбрать

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

Сумма(Продажи.СуммаОборот) Как Сумма

Из

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

Где

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

Сгруппировать По

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

Здесь ГДЕ отсекает лишние строки до группировки. Это важно и для производительности: чем раньше отфильтрованы данные, тем меньше записей участвует в группировке и соединениях.

Ключевое ограничение: в ГДЕ нельзя использовать агрегатные функции. Конструкция ГДЕ Сумма(Продажи.СуммаОборот) > 1000 вызовет ошибку, потому что на момент применения ГДЕ суммы ещё не вычислены.

Что делает оператор ИМЕЮЩИЕ

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

Классическая задача — найти товары, сумма продаж которых превышает порог:

Выбрать

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

Сумма(Продажи.СуммаОборот) Как Сумма

Из

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

Сгруппировать По

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

Имеющие

Сумма(Продажи.СуммаОборот) > 100000

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

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

Ключевые отличия ГДЕ и ИМЕЮЩИЕ

Различия удобно свести в таблицу — по ней легко проверить себя при написании запроса.

КритерийГДЕИМЕЮЩИЕ
Этап примененияДо группировкиПосле группировки
Что фильтруетСтроки исходных таблицСгруппированные итоги
Агрегатные функцииЗапрещеныРазрешены
Требует СГРУППИРОВАТЬ ПОНетДа, работает с группировкой
Влияние на скоростьСокращает объём данных на раннем этапеФильтрует уже обработанные группы

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

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

ГДЕ

Подходит для отбора по обычным полям: организация, период, номенклатура, признаки. Не работает с итогами группировки.

ИМЕЮЩИЕ

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

Примеры типовых задач

Поиск дублей в справочнике

Найти элементы справочника с одинаковыми наименованиями можно только через ИМЕЮЩИЕ, потому что условие накладывается на количество записей в группе:

Выбрать

Контрагенты.Наименование,

Количество(Контрагенты.Ссылка) Как КоличествоДублей

Из

Справочник.Контрагенты Как Контрагенты

Сгруппировать По

Контрагенты.Наименование

Имеющие

Количество(Контрагенты.Ссылка) > 1

Отбор по обычному полю и по итогу одновременно

Оба оператора можно сочетать в одном запросе. Например, показать клиентов конкретного региона, у которых сумма продаж превысила порог:

Выбрать

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

Сумма(Продажи.СуммаОборот) Как Сумма

Из

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

Где

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

Сгруппировать По

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

Имеющие

Сумма(Продажи.СуммаОборот) > &Порог

Здесь ГДЕ отсекает чужие регионы до группировки, а ИМЕЮЩИЕ убирает группы с маленькими итогами. Каждый оператор делает свою работу на своём этапе.

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

Типичные ошибки и ограничения

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

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

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

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

Влияние на производительность

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

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

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

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

Запрос выполняется без ошибок
Норма

Нет сообщений про агрегатные функции в условии

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

Ошибка «Агрегатная функция не может использоваться в условии» — функция попала в ГДЕ

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

Совпадает с ручным подсчётом на тестовых данных

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

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

Время выполнения на большой таблице
Норма

Условия по полям — в ГДЕ или в параметрах виртуальной таблицы

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

Все условия собраны в ИМЕЮЩИЕ — группируется лишний объём

FAQ

Можно ли использовать ИМЕЮЩИЕ без ГДЕ?

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

Можно ли в ИМЕЮЩИЕ ссылаться на псевдоним поля из секции ВЫБРАТЬ?

Надёжнее повторять саму агрегатную функцию: Сумма(Продажи.СуммаОборот) > 1000. Поведение при использовании псевдонимов в ИМЕЮЩИЕ зависит от версии платформы, а запись с явной функцией работает всегда.

Чем ИМЕЮЩИЕ отличается от отбора во временной таблице?

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

Работает ли ГДЕ с итогами по иерархии (ИТОГИ ПО)?

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

Почему условие в ИМЕЮЩИЕ с параметром иногда не отбирает записи?

Частая причина — NULL в результате агрегатной функции (например, СУММА по пустому набору даёт NULL). Сравнение NULL с числом всегда ложно. Оберните функцию в ЕСТЬNULL: ЕстьNull(Сумма(...), 0) > &Порог.

Итог

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

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