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

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

Оператор ВЫБОР КОГДА в запросе 1С: применение и примеры

Как работает оператор ВЫБОР КОГДА (аналог CASE WHEN) в языке запросов 1С: синтаксис, примеры, типичные ошибки, использование в СКД и отчётах.

Оператор ВЫБОР … КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ — это аналог конструкции CASE WHEN из классического SQL, встроенный в язык запросов 1С. Он позволяет формировать в результате запроса вычисляемое поле, значение которого зависит от условий: статус документа, категория номенклатуры, признак просрочки и тому подобное. Без этого оператора разработчику пришлось бы делать несколько запросов или обрабатывать результат в коде, что медленнее и сложнее в сопровождении.

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

Синтаксис оператора ВЫБОР

Полная форма оператора выглядит так:

ВЫБОР

КОГДА <Условие1> ТОГДА <Значение1>

КОГДА <Условие2> ТОГДА <Значение2>

ИНАЧЕ <ЗначениеПоУмолчанию>

КОНЕЦ

Платформа проверяет условия последовательно сверху вниз. Как только встречается первое истинное условие, возвращается соответствующее значение, а остальные ветки не вычисляются. Если ни одно условие не выполнено, возвращается значение из секции ИНАЧЕ. Если ИНАЧЕ не указано и ни одно условие не сработало — результатом будет NULL.

Есть и сокращённая форма с одним условием, но в практике она используется редко — чаще встречается полная запись даже для одного КОГДА, потому что она читается единообразно. Условие в КОГДА — это любое логическое выражение, допустимое в запросе: сравнения, И/ИЛИ, проверка В ИЕРАРХИИ, сравнение с параметром.

Простой пример: текстовый статус вместо признака

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

ВЫБРАТЬ

РеализацияТоваровУслуг.Номер КАК Номер,

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

ВЫБОР

КОГДА РеализацияТоваровУслуг.Проведен

ТОГДА "Проведён"

ИНАЧЕ "Не проведён"

КОНЕЦ КАК Статус

ИЗ

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

Обратите внимание на псевдоним КАК Статус после КОНЕЦ — без него поле получит служебное имя, и обратиться к нему в СКД или при обходе выборки будет неудобно. Всегда давайте вычисляемым полям осмысленные имена.

Несколько условий и порядок их проверки

Когда условий несколько, критично помнить: проверка идёт сверху вниз, и более частные условия нужно ставить выше общих. Если перепутать порядок, широкое условие «перехватит» записи раньше узкого, и результат будет неверным без какой-либо ошибки выполнения.

ВЫБОР

КОГДА Продажи.СуммаОборот >= 1000000

ТОГДА "VIP"

КОГДА Продажи.СуммаОборот >= 100000

ТОГДА "Крупный"

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

ТОГДА "Обычный"

ИНАЧЕ "Без продаж"

КОНЕЦ КАК КатегорияКлиента

В этом примере диапазоны перекрываются: клиент с оборотом 1 500 000 формально удовлетворяет всем трём условиям, но попадёт в «VIP», потому что это условие стоит первым. Если бы строка «Обычный» была первой, все клиенты с продажами получили бы именно её.

В условиях допустимы составные выражения:

КОГДА Заказ.Проведен

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

И Заказ.ДатаОтгрузки <= &ТекущаяДата

ТОГДА "К отгрузке"

Типичные ошибки
01
Неправильный порядок условий: широкое условие стоит выше узкого и перехватывает записи, ошибка не выдаётся — результат просто неверный
02
Разные типы значений в ТОГДА и ИНАЧЕ: строка в одной ветке и число в другой приводит к ошибке запроса или неявному приведению
03
Отсутствие ИНАЧЕ: записи, не попавшие ни в одно условие, получают NULL, что ломает группировки и соединения
04
Сравнение с NULL через знак равенства: NULL = NULL ложно, нужно использовать ЕСТЬ NULL или ЕСТЬNULL

Требование совместимости типов

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

Если нужно показать в одном поле и ссылку, и текст, приведите всё к строке через функцию ПРЕДСТАВЛЕНИЕ(). Для чисел разной длины и точности проблем обычно нет — платформа приведёт их к общему числовому типу. А вот комбинация «дата + строка» или «ссылка + булево» гарантированно вызовет ошибку.

Отдельный нюанс — NULL в ветках. Если одна из веток возвращает NULL (например, поле из левого соединения), а другая — конкретное значение, запрос выполнится, но для надёжности лучше обернуть поле в ЕСТЬNULL():

ВЫБОР

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

ТОГДА 0

ИНАЧЕ ЕСТЬNULL(Остатки.КоличествоОстаток, 0)

КОНЕЦ КАК Остаток

ВЫБОР в группировках, итогах и соединениях

Оператор можно использовать не только в списке выборки. Три частых сценария:

  • Группировка по вычисляемой категории. Сначала во временной таблице или подзапросе вычисляется категория через ВЫБОР, затем по ней строится ГРУППИРОВАТЬ ПО с суммированием. Группировать непосредственно по выражению ВЫБОР в том же запросе платформа тоже позволяет, но читаемость страдает.
  • Условные агрегаты. Приём «сумма только нужных строк»: СУММА(ВЫБОР КОГДА Условие ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ). Так в одном запросе считают, например, отдельно суммы отгруженных и неотгруженных заказов без двух соединений.
  • Условие соединения и отбор. ВЫБОР допустим в секции ГДЕ и в условиях соединения, но там его лучше заменять на прямые логические выражения — оптимизатор СУБД справляется с ними эффективнее.
ВЫБРАТЬ

Заказы.Контрагент КАК Контрагент,

СУММА(ВЫБОР

КОГДА Заказы.Отгружен

ТОГДА Заказы.Сумма

ИНАЧЕ 0

КОНЕЦ) КАК СуммаОтгружено,

СУММА(ВЫБОР

КОГДА НЕ Заказы.Отгружен

ТОГДА Заказы.Сумма

ИНАЧЕ 0

КОНЕЦ) КАК СуммаНеОтгружено

ИЗ

Документ.ЗаказПокупателя КАК Заказы

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

Заказы.Контрагент

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

ВЫБОР в СКД и динамических списках

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

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

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

Чем заменить ВЫБОР

Логические выражения в ГДЕ

Подходит для отбора записей. Компактнее и лучше оптимизируется, но не умеет возвращать разные значения

Соединение с таблицей-периодикой или регистром

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

Функция ЕСТЬNULL()

Частный случай ВЫБОР с проверкой на NULL — пишется короче и читается проще

Вычисляемое поле в СКД

Подходит для чисто отображаемых значений, но такое поле нельзя использовать в отборах и группировках запроса

Производительность и ограничения

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

Рекомендации по оптимизации:

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

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

Можно ли использовать ВЫБОР в секции ИТОГИ?

Напрямую — нет, итоги строятся по полям запроса. Но можно вычислить поле через ВЫБОР в списке выборки, а затем указать его в секции ИТОГИ ПО — это рабочий и распространённый приём для группировки по категориям.

Чем ВЫБОР отличается от ЕСТЬNULL?

ЕСТЬNULL — частный случай: проверяет единственное выражение на NULL и подставляет замену. ВЫБОР универсальнее — проверяет любые условия и возвращает разные значения. Если задача сводится к замене NULL, используйте ЕСТЬNULL: запись короче и понятнее.

Можно ли в условии КОГДА использовать параметры запроса?

Да, параметры (&ИмяПараметра) допустимы и в условиях, и в возвращаемых значениях. Тип параметра должен быть совместим с типом сравниваемого поля — несовпадение типов вызовет ошибку при выполнении запроса.

Почему запрос с ВЫБОР возвращает NULL, хотя ИНАЧЕ задано?

Чаще всего причина не в операторе, а в том, что NULL приходит из соединения и попадает в само условие: сравнение с NULL даёт ложь, и запись уходит в ИНАЧЕ — но если ИНАЧЕ возвращает поле из того же соединения, оно тоже NULL. Проверьте ветку ИНАЧЕ и оберните поля в ЕСТЬNULL.

Работает ли ВЫБОР в запросах к внешним источникам данных?

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

Есть ли ограничение на число веток КОГДА?

Жёсткого документированного предела нет, запросы с десятками веток выполняются. Однако длинный список условий — признак того, что соответствие значений лучше вынести в данные (справочник или регистр сведений) и получать соединением.

Итог

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

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