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

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

Оператор ГДЕ в языке запросов 1С 8: как правильно ставить условия

Как использовать условие ГДЕ в запросах 1С 8: синтаксис, сравнение значений, В(), ПОДОБНО, NULL, виртуальные таблицы, типичные ошибки и примеры кода.

Условие ГДЕ — основной инструмент отбора данных в языке запросов 1С 8. Именно оно определяет, какие строки попадут в результат, а какие будут отброшены. Ошибка в условии приводит либо к пустой выборке, либо к лишним записям, либо к заметному падению производительности, поэтому разработчику важно понимать не только синтаксис, но и то, как платформа исполняет запрос на стороне СУБД.

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

Материал ориентирован на практику: разобраны рабочие примеры кода, особенности сравнения разных типов данных, фильтрация в виртуальных таблицах и типичные ошибки, из-за которых запрос возвращает не то, что ожидалось.

Синтаксис оператора ГДЕ и простые условия

Базовая форма условия — сравнение поля со значением или параметром. Параметры в тексте запроса обозначаются символом «&» и заполняются через метод УстановитьПараметр объекта Запрос. Жёстко прописывать значения в тексте запроса не принято: это затрудняет сопровождение и не даёт платформе повторно использовать план запроса.

Пример отбора документов по контрагенту и дате:

ВЫБРАТЬ

Реализация.Номер,

Реализация.Дата,

Реализация.СуммаДокумента

ИЗ

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

ГДЕ

Реализация.Контрагент = &Контрагент

И Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода

И НЕ Реализация.ПометкаУдаления

Оператор МЕЖДУ включает граничные значения, поэтому важно корректно задавать конец периода — обычно через КонецПериода() встроенного языка или функцию запроса КОНЕЦПЕРИОДА(&Дата, ДЕНЬ). Если передать просто дату без времени, документы за последний день, проведённые после 00:00:00, в выборку не попадут — это одна из самых частых причин «потерянных» данных.

bsl
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Сравнение значений: типы, NULL и составные поля

При сравнении платформа учитывает тип значения. Сравнение строки с числом не вызовет ошибки, но и не найдёт совпадений. Особое внимание требуют поля составного типа: если реквизит может хранить ссылки разных справочников, сравнение с параметром одного типа отработает, однако сравнение с параметром, содержащим Неопределено, даст неочевидный результат.

Проверка на NULL

Значение NULL появляется в результате левых соединений, когда в присоединяемой таблице нет подходящей строки. Сравнивать его через «= NULL» нельзя — такое условие всегда ложно. Используется специальная конструкция:

ГДЕ

Остатки.КоличествоОстаток ЕСТЬ NULL

Обратная проверка — ЕСТЬ НЕ NULL. Если нужно заменить NULL на значение по умолчанию в списке выборки, применяется функция ЕСТЬNULL(Поле, 0). Это особенно важно перед арифметическими операциями: любое вычисление с NULL даёт NULL, и суммы в отчёте «молча» теряются.

Логика условий: И, ИЛИ, НЕ и скобки

Оператор И имеет приоритет над ИЛИ, поэтому условие А И Б ИЛИ В трактуется как (А И Б) ИЛИ В. При смешивании И и ИЛИ скобки ставить обязательно — иначе логика запроса будет отличаться от задуманной, и найти такую ошибку по косвенным признакам бывает трудно.

Типовой пример с группировкой условий:

ГДЕ

(Номенклатура.ВидНоменклатуры = &ВидТовар

ИЛИ Номенклатура.ВидНоменклатуры = &ВидУслуга)

И НЕ Номенклатура.ЭтоГруппа

И НЕ Номенклатура.ПометкаУдаления

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

Отбор по спискам и шаблонам: В, В ИЕРАРХИИ, ПОДОБНО

Для проверки вхождения значения в список используется оператор В. В качестве списка передаётся массив, список значений или таблица значений через параметр:

ГДЕ

Товары.Номенклатура В (&СписокНоменклатуры)

Для иерархических справочников есть вариант В ИЕРАРХИИ — он отбирает элементы, входящие в указанную группу на любом уровне вложенности. Это стандартный способ отбора товаров по папке номенклатуры без рекурсивных обходов в коде.

Оператор ПОДОБНО выполняет сравнение строки с шаблоном: символ «%» заменяет любую последовательность символов, «_» — один символ. Пример поиска по фрагменту наименования:

ГДЕ

Номенклатура.Наименование ПОДОБНО "%кабель%"

Учтите ограничение: ПОДОБНО с шаблоном, начинающимся с «%», не может использовать индекс, и на больших таблицах такой запрос приведёт к полному сканированию. Если поиск по подстроке нужен регулярно, рассмотрите полнотекстовый поиск или отдельные служебные поля.

Запрос работает медленноВозможно, фильтр стоит не там

Проверьте, не фильтруете ли вы виртуальную таблицу через ГДЕ вместо параметров

Пустой результатУсловие отсекает все строки

Проверьте NULL, типы параметров и границы периода

Лишние строкиОшибка в логике И/ИЛИ

Расставьте скобки и проверьте каждое условие по отдельности

ГДЕ и виртуальные таблицы: где ставить фильтр

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

Сравнение двух подходов:

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

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

РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) — отбор выполняется на уровне СУБД при построении таблицы, быстро и экономно.

Условие в секции ГДЕ

ГДЕ Остатки.Склад = &Склад — виртуальная таблица строится по всем складам, потом фильтруется. На больших регистрах это кратно медленнее.

Пример правильного запроса:

ВЫБРАТЬ

Остатки.Номенклатура,

Остатки.КоличествоОстаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(

&Период,

Склад = &Склад

И Номенклатура В (&СписокНоменклатуры)) КАК Остатки

ГДЕ

Остатки.КоличествоОстаток > 0

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

Параметры, вложенные запросы и проверка результата

Все внешние значения передаются через параметры. Перед выполнением проверьте, что каждый параметр установлен: неустановленный параметр вызовет ошибку «Переменная не определена». Если параметр может быть пустым списком, учтите, что условие В (&ПустойСписок) не вернёт ни одной строки — иногда это желаемое поведение, иногда источник ошибки.

В секции ГДЕ допустимы вложенные запросы, например отбор документов, по которым есть движения:

ГДЕ

Реализация.Ссылка В

(ВЫБРАТЬ РАЗЛИЧНЫЕ

Движения.Регистратор

ИЗ

РегистрНакопления.Продажи КАК Движения

ГДЕ

Движения.Период МЕЖДУ &Начало И &Конец)

Порядок действий при написании условия
  1. 1
    Определите, какие строки должны попасть в результат, и сформулируйте условие словами
  2. 2
    Проверьте типы сравниваемых полей и параметров — они должны совпадать
  3. 3
    Фильтры по измерениям регистра перенесите в параметры виртуальной таблицы
  4. 4
    Сгруппируйте условия И/ИЛИ скобками по задуманной логике
  5. 5
    Выполните запрос в консоли запросов на тестовых данных и сверьте количество строк с ожидаемым
  6. 6
    Проверьте крайние случаи: пустой список, NULL, границы периода

Типичные ошибки при использовании ГДЕ

Большинство проблем с условиями повторяются от проекта к проекту. Знание типовых сценариев экономит часы отладки.

Типичные ошибки
01
Сравнение с NULL через «=» — условие всегда ложно; используйте ЕСТЬ NULL
02
Конец периода без времени — теряются документы последнего дня; применяйте КонецДня() или КОНЕЦПЕРИОДА
03
Фильтр по измерениям регистра в ГДЕ вместо параметров виртуальной таблицы — резкое падение скорости
04
Отсутствие скобок при смешении И и ИЛИ — логика запроса отличается от задуманной
05
Сравнение полей разных типов без ВЫРАЗИТЬ — тихий пустой результат
06
ПОДОБНО с «%» в начале на большой таблице — полное сканирование и блокировки

Отдельно стоит упомянуть функцию ВЫРАЗИТЬ: она приводит значение к нужному типу прямо в запросе, например ГДЕ ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент = &Контрагент. Это рабочий приём для составных полей, но злоупотреблять им не стоит — приведение типа может мешать использованию индексов.

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

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

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

Совпадает с контрольной выборкой в интерфейсе

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

Строк меньше — проверяйте NULL, период и типы параметров

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

Запрос отрабатывает быстро на реальном объёме данных

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

Медленно — фильтры регистра вынесены из параметров виртуальной таблицы

Данные за граничные даты
Норма

Документы первого и последнего дня периода присутствуют

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

Последний день пуст — некорректная граница периода

Когда ГДЕ недостаточно: альтернативы

Не всякий отбор решается секцией ГДЕ. Если нужно отфильтровать уже сгруппированные данные (например, только контрагентов с суммой продаж выше порога), используется секция ИМЕЮЩИЕ — она работает после группировки, как HAVING в SQL. Условие вида ИМЕЮЩИЕ СУММА(Продажи.Сумма) > &Порог в ГДЕ написать нельзя.

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

Итог

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

ГДЕ фильтрует строки после источника: используйте параметры через &, проверки NULL через ЕСТЬ NULL, списки через В, шаблоны через ПОДОБНО. Отборы по измерениям регистров задавайте в параметрах виртуальных таблиц, а логику И/ИЛИ всегда фиксируйте скобками. Проверяйте результат в консоли запросов на граничных случаях.

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

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

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

Как в условии ГДЕ проверить, что параметр не заполнен?

Для ссылочных типов сравните параметр с пустой ссылкой через ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) или передайте пустую ссылку параметром. Для строк — сравнение с пустой строкой, для дат — с ДАТАВРЕМЯ(1,1,1). Универсальный приём — условие вида (&Параметр = &ПустоеЗначение ИЛИ Поле = &Параметр), когда пустой параметр должен отключать фильтр.

Можно ли в ГДЕ использовать функции встроенного языка?

Нет, в тексте запроса доступны только функции языка запросов: ЕСТЬNULL, ВЫРАЗИТЬ, ПРЕДСТАВЛЕНИЕ, КОНЕЦПЕРИОДА, РАЗНОСТЬДАТ и другие из документированного списка. Если нужна логика встроенного языка — вычислите значение заранее и передайте его параметром.

Почему условие В (&Список) не возвращает строки при пустом списке?

Потому что ни одно значение не входит в пустое множество — это корректное поведение оператора В. Если пустой список должен означать «без отбора», добавьте проверку: ГДЕ (&СписокПуст ИЛИ Поле В (&Список)), где &СписокПуст — булев параметр, вычисленный в коде по количеству элементов списка.

Влияет ли порядок условий в ГДЕ на скорость запроса?

Как правило, нет: оптимизатор СУБД сам выбирает порядок вычисления условий и используемые индексы. На скорость влияют не порядок строк в тексте, а наличие подходящих индексов, отсутствие функций над индексированными полями и правильное размещение фильтров в параметрах виртуальных таблиц.

Как отладить сложное условие ГДЕ?

Откройте запрос в консоли запросов, установите реальные значения параметров и временно уберите все условия, кроме одного. Затем добавляйте условия по одному, контролируя количество строк после каждого шага. Так быстро находится условие, которое отсекает нужные данные. Для проверки промежуточных результатов удобно выводить поля условия в список выборки.