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