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

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

ВЫБОР В ГДЕ в запросах 1С 8: синтаксис и практические приёмы

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

Конструкция ВЫБОР в языке запросов 1С 8 — это аналог оператора CASE: она позволяет вычислить значение по условиям прямо внутри запроса. Чаще всего её применяют в секции выборки полей, но не менее полезна она и в секции ГДЕ — когда условие отбора должно зависеть от значения параметра или от данных самой строки. Такой приём называют «ВЫБОР В ГДЕ».

Типичная задача выглядит так: пользователь заполнил отбор в отчёте — фильтруем по нему, не заполнил — показываем всё. Без ВЫБОР пришлось бы собирать текст запроса строками или плодить несколько вариантов запроса. С ВЫБОР В ГДЕ один универсальный запрос закрывает оба сценария, что упрощает сопровождение кода и снижает риск расхождений между ветками логики.

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

Синтаксис конструкции ВЫБОР и её место в секции ГДЕ

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

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

ГДЕ

ВЫБОР

КОГДА &Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

ТОГДА ИСТИНА

ИНАЧЕ Товары.Склад = &Склад

КОНЕЦ

Обратите внимание: внутри КОГДА пишется полноценное логическое выражение, включая И, ИЛИ, НЕ и вложенные ВЫБОР. Это позволяет строить составные условия, но чрезмерная вложенность быстро делает запрос нечитаемым — больше двух уровней вкладывать не стоит.

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

Самая частая задача — «если параметр задан, фильтруем; если пустой, не фильтруем». Проблема в том, что «пустой» в 1С бывает разным: пустая ссылка, НЕОПРЕДЕЛЕНО, пустая строка, нулевая дата. Условие в КОГДА должно проверять именно тот признак пустоты, который соответствует типу параметра.

Для ссылочных типов проверяют сравнением с пустой ссылкой через ЗНАЧЕНИЕ(...) или с НЕОПРЕДЕЛЕНО, если параметр может быть не заполнен вовсе. Для строк — сравнение с пустой строкой. Для дат — с датой '00010101'. Универсального «пустого значения» в запросах нет, и это источник большинства ошибок.

ГДЕ

ВЫБОР

КОГДА &Организация = НЕОПРЕДЕЛЕНО

ТОГДА ИСТИНА

ИНАЧЕ Продажи.Организация = &Организация

КОНЕЦ

И ВЫБОР

КОГДА &Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

ТОГДА ИСТИНА

ИНАЧЕ Продажи.Контрагент = &Контрагент

КОНЕЦ

Несколько условных отборов соединяются обычным И. Каждый ВЫБОР отвечает за свой параметр, и незаполненные параметры просто «выключаются» через ветку ТОГДА ИСТИНА. Такой запрос легко расширять: новый отбор — это ещё один блок ВЫБОР, а не новая ветка программного кода.

Как добавить условный отбор в запрос
  1. 1
    Определите тип параметра и его «пустое» состояние: пустая ссылка, НЕОПРЕДЕЛЕНО, пустая строка или пустая дата
  2. 2
    Напишите ВЫБОР: в КОГДА проверьте пустоту параметра, в ТОГДА верните ИСТИНА, в ИНАЧЕ — сравнение поля с параметром
  3. 3
    Соедините блок с остальными условиями через И
  4. 4
    Прогоните запрос в консоли запросов с заполненным и с пустым параметром и сравните число строк

ВЫБОР, возвращающий значение для сравнения

Второй шаблон — ВЫБОР вычисляет не булево, а значение, с которым сравнивается поле. Это удобно, когда порог или эталон зависит от данных строки: например, для одних категорий товаров норматив один, для других — другой.

ГДЕ

Остатки.Количество < ВЫБОР

КОГДА Товары.Категория = ЗНАЧЕНИЕ(Перечисление.Категории.Ходовые)

ТОГДА 10

КОГДА Товары.Категория = ЗНАЧЕНИЕ(Перечисление.Категории.Редкие)

ТОГДА 2

ИНАЧЕ 5

КОНЕЦ

Здесь критично правило совместимости типов: все ветки ТОГДА и ИНАЧЕ должны возвращать значения одного типа (или типов, приводимых друг к другу). Если одна ветка возвращает число, а другая — строку, запрос либо не выполнится, либо поведёт себя непредсказуемо в зависимости от СУБД. Числовые ветки желательно приводить к одной разрядности через ВЫРАЗИТЬ.

Также помните про NULL в сравниваемом поле. Если Остатки.Количество равно NULL (например, после левого соединения), всё сравнение даст NULL, и строка выпадет из результата независимо от ВЫБОР. Защита — обернуть поле в ЕСТЬNULL(Поле, 0).

Работа с NULL и левыми соединениями

NULL — главный источник «тихих» ошибок в условных отборах. Сравнение NULL с чем угодно, включая NULL = NULL, даёт не ИСТИНА и не ЛОЖЬ, а NULL. В секции ГДЕ это означает отбрасывание строки без какого-либо сообщения об ошибке. Запрос выполняется успешно, но данных в нём меньше, чем ожидалось.

Если ВЫБОР строится на полях из левого соединения, каждое такое поле потенциально NULL. Перед сравнением применяйте ЕСТЬNULL с осмысленным значением по умолчанию. Альтернатива — проверка «Поле ЕСТЬ NULL» внутри КОГДА, если отсутствие связанной записи нужно трактовать отдельной веткой логики.

ГДЕ

ВЫБОР

КОГДА ДопСвойства.Ставка ЕСТЬ NULL

ТОГДА Продажи.Сумма > 0

ИНАЧЕ Продажи.Сумма > ЕСТЬNULL(ДопСвойства.Ставка, 0)

КОНЕЦ

Тот же принцип действует для параметров составного типа. Если параметр объявлен как «справочник или документ», сравнение поля с параметром другого типа вернёт ЛОЖЬ, а не ошибку — и фильтр молча отсечёт все строки. Проверяйте тип параметра через ТИПЗНАЧЕНИЯ или сужайте составной тип через ВЫРАЗИТЬ.

Производительность: когда ВЫБОР В ГДЕ вредит

У удобства есть цена. Условие вида «Поле = &Параметр» позволяет СУБД использовать индекс по полю. Условие, обёрнутое в ВЫБОР, — это вычисляемое выражение, и оптимизатор чаще всего не может применить индекс: выполняется полное сканирование таблицы с вычислением ВЫБОР для каждой строки. На больших таблицах (регистры накопления с миллионами записей) разница по времени может быть многократной.

Более производительная альтернатива для сценария «параметр задан / не задан» — объединение через ИЛИ: ГДЕ (&Параметр = НЕОПРЕДЕЛЕНО ИЛИ Поле = &Параметр). Многие СУБД оптимизируют такую конструкцию лучше, чем ВЫБОР. Ещё один вариант — параметр-список с условием «Поле В (&Список)», где в список заранее помещают либо одно значение, либо все допустимые.

Практический критерий прост: если таблица небольшая (справочники, небольшие регистры сведений), ВЫБОР В ГДЕ безопасен и удобен. Если запрос идёт по крупному регистру и выполняется часто, сначала замерьте время на реальных данных и сравните с вариантом через ИЛИ или с программной сборкой текста запроса.

Способы условного отбора

ВЫБОР В ГДЕ

Один универсальный запрос, читаемый код. Минус: обычно не использует индекс, медленнее на больших таблицах.

Условие через ИЛИ

ГДЕ (&П = НЕОПРЕДЕЛЕНО ИЛИ Поле = &П). Часто лучше оптимизируется СУБД, но текст громоздче при множестве параметров.

Программная сборка текста запроса

Максимальная скорость: в текст попадают только реально нужные условия. Минус: сложнее сопровождать и отлаживать.

Отборы СКД

Для отчётов на компоновке данных условные отборы решаются настройками СКД без ВЫБОР в тексте запроса.

Проверка результата и типичные ошибки

Проверять условный запрос нужно минимум в трёх режимах: параметр заполнен, параметр пуст, параметр содержит значение, которого нет в данных. В первом случае отбор обязан сработать, во втором — вернуть полный набор, в третьем — честно вернуть пустой результат, а не все строки. Расхождение в любом из режимов указывает на ошибку в ветках ВЫБОР.

Типичные ошибки
01
Сравнение ссылочного параметра с НЕОПРЕДЕЛЕНО, когда на самом деле передаётся пустая ссылка — условие «пустоты» никогда не срабатывает, фильтр отсекает все строки
02
Отсутствие ветки ИНАЧЕ: при несработавших КОГДА ВЫБОР возвращает NULL, и строки молча выпадают из выборки
03
Разные типы в ветках ТОГДА и ИНАЧЕ — ошибка выполнения запроса на уровне СУБД или непредсказуемое приведение типов
04
Сравнение поля, содержащего NULL после левого соединения, без ЕСТЬNULL — потеря строк без каких-либо сообщений
05
Возврат из ВЫБОР не булева, а значения, которое затем ничем не сравнивается: ГДЕ ВЫБОР ... ТОГДА 1 КОНЕЦ — такое условие работает не так, как ожидает автор

Ещё одна ловушка — приоритет операторов. Если ВЫБОР в ГДЕ соседствует с ИЛИ, оборачивайте каждое составное условие в скобки. Без скобок И связывает сильнее, чем ИЛИ, и логика отбора меняется незаметно для автора.

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

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

Запрос с заполненным параметром
Норма

Возвращаются только строки, удовлетворяющие отбору

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

Пустой результат при заведомо существующих данных — проверяйте тип параметра и признак «пустоты»

Запрос с пустым параметром
Норма

Возвращается полный набор строк без фильтрации

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

Ноль строк — ветка ТОГДА ИСТИНА не срабатывает, условие КОГДА проверяет не то значение

Строки с NULL в полях соединения
Норма

Строки обрабатываются согласно задуманной логике

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

Строки пропадают — добавьте ЕСТЬNULL или проверку ЕСТЬ NULL

Альтернативы и границы применения

ВЫБОР В ГДЕ — не единственный инструмент условной логики. В отчётах на СКД условные отборы правильнее реализовывать через настройки компоновки: пользователь сам включает и отключает отборы, а запрос остаётся простым и быстрым. ВЫБОР в тексте запроса СКД имеет смысл только для вычисляемой логики, которую нельзя выразить стандартным отбором.

Для динамических списков и подборов, где набор отборов заранее неизвестен, надёжнее программная сборка запроса или установка параметров построителя. ВЫБОР оправдан, когда число варьируемых условий невелико (один–пять параметров) и их комбинации заранее понятны.

Маршрут решения

Как выбрать подход

Отчёт на СКД, отборы задаёт пользовательИспользуйте отборы в настройках СКД, ВЫБОР в тексте запроса не нужен
1–5 параметров, запрос по небольшой таблицеПрименяйте ВЫБОР В ГДЕ — это читаемо и достаточно быстро
Запрос по крупному регистру, критична скоростьСравните с вариантом через ИЛИ или собирайте текст запроса программно
Набор условий заранее неизвестенСобирайте запрос динамически, ВЫБОР здесь не подходит

FAQ

Можно ли использовать несколько КОГДА внутри ВЫБОР в секции ГДЕ?

Да, количество ветвей КОГДА не ограничено. Условия проверяются сверху вниз, срабатывает первая истинная ветка. Следите, чтобы все ветки возвращали один и тот же тип — для секции ГДЕ это булево.

Почему запрос с ВЫБОР В ГДЕ возвращает пустой результат, хотя данные есть?

Чаще всего причина в несовпадении «пустого» значения: параметр содержит пустую ссылку, а условие проверяет НЕОПРЕДЕЛЕНО, или наоборот. Вторая частая причина — NULL в сравниваемом поле после левого соединения. Проверьте запрос в консоли с явно заданными значениями параметров.

Обязательна ли ветка ИНАЧЕ?

Синтаксически — нет, но без неё при несрабатывании всех КОГДА ВЫБОР вернёт NULL, и в секции ГДЕ строка будет отброшена. Для условий отбора ветку ИНАЧЕ стоит писать всегда, явно указывая ИСТИНА или ЛОЖЬ.

Что быстрее: ВЫБОР В ГДЕ или условие через ИЛИ?

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

Можно ли вкладывать один ВЫБОР внутрь другого?

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

Работает ли ВЫБОР В ГДЕ в динамических списках форм?

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

Итог

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

ВЫБОР В ГДЕ — способ сделать отбор условным в одном запросе: в КОГДА проверяется признак пустоты параметра, в ТОГДА возвращается ИСТИНА, в ИНАЧЕ — реальное сравнение. Следите за совместимостью типов веток, обрабатывайте NULL через ЕСТЬNULL и помните: на больших таблицах вариант через ИЛИ или программная сборка запроса часто быстрее.