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

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

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

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

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

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

Синтаксис конструкции ВЫБОР КОГДА

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

ВЫБОР

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

ТОГДА "Крупная"

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

ТОГДА "Средняя"

ИНАЧЕ "Мелкая"

КОНЕЦ КАК КатегорияСделки

Если ни одно условие не выполнилось и ветка ИНАЧЕ отсутствует, поле получит значение NULL. Это частый источник ошибок: разработчик забывает ИНАЧЕ, а потом удивляется пустым значениям в отчёте. Поэтому правило простое — всегда явно указывайте ИНАЧЕ, даже если возвращаете пустую строку или ноль.

Простые условия и сравнение со ссылками

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

ВЫБОР

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

ТОГДА "Ожидает обработки"

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

ТОГДА "Выполнен"

ИНАЧЕ "В работе"

КОНЕЦ КАК СтатусТекстом

Обратите внимание: сравнивать ссылочные значения нужно с конкретными значениями, полученными через ЗНАЧЕНИЕ() или параметр запроса. Сравнение ссылки со строковым представлением («Закрыт») не сработает — условие просто никогда не будет истинным, и вы всегда попадёте в ветку ИНАЧЕ.

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

Работа с NULL и замена пустых значений

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

ВЫБОР

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

ТОГДА 0

ИНАЧЕ Остатки.КоличествоОстаток

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

Для простой замены NULL удобнее функция ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) — она короче и читается легче. Но ВЫБОР гибче: через него можно проверить сразу несколько условий, например отдельно обработать NULL, ноль и отрицательные значения с разными результатами.

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

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

СУММА(ВЫБОР

КОГДА Обороты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)

ТОГДА Обороты.Количество

ИНАЧЕ 0

КОНЕЦ) КАК Приход

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

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

Требования к типам возвращаемых значений

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

Отдельная тонкость — ссылочные типы. Если одна ветка возвращает ссылку на справочник «Номенклатура», а другая — на «Контрагенты», поле получит составной тип. Это допустимо, но усложнит дальнейшую обработку результата и может замедлить запрос. По возможности унифицируйте типы на этапе проектирования запроса.

Строки в разных ветках тоже стоит приводить к одинаковой длине через ВЫРАЗИТЬ(... КАК Строка(50)), иначе итоговый тип поля может получить неожиданную длину, что критично при помещении результата во временную таблицу с последующим соединением.

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

Производительность и порядок условий

Порядок веток КОГДА имеет двойное значение. Во-первых, логическое: проверка идёт сверху вниз, и первое истинное условие «перехватывает» строку. Если ветка «Сумма >= 10000» стоит выше, чем «Сумма >= 100000», крупные сделки никогда не попадут в свою категорию. Всегда располагайте более строгие условия выше.

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

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

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

Проверка результата и отладка

Отлаживать ВЫБОР удобнее всего в консоли запросов: выведите рядом с вычисляемым полем исходные поля, участвующие в условиях. Так сразу видно, почему строка попала в конкретную ветку, и не «съело» ли верхнее условие строки, предназначенные для нижнего.

Дополнительный приём — временно добавить в выборку номер сработавшей ветки отдельным полем (числа 1, 2, 3 в ветках ТОГДА). После отладки это служебное поле удаляется. Такой способ быстро выявляет строки, уходящие в ИНАЧЕ из-за NULL в исходных данных.

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

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

Количество строк с каждым значением вычисляемого поля
Норма

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

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

Все строки попали в ИНАЧЕ — вероятно, условия не срабатывают

Наличие NULL в итоговом поле
Норма

NULL отсутствуют или появляются только осознанно

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

NULL там, где ожидалось значение — забыта ветка ИНАЧЕ

Тип итогового поля
Норма

Однородный тип во всех строках

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

Смешанные типы — ветки возвращают несовместимые значения

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

Сопоставимо с аналогичным запросом без ВЫБОР

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

Кратный рост времени — условия обращаются к соединённым таблицам или отключили индексы

Часто задаваемые вопросы

Чем ВЫБОР КОГДА отличается от функции ЕСТЬNULL?

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

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

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

Работает ли ВЫБОР в секции ИТОГИ и при группировке?

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

Почему условие с перечислением никогда не срабатывает?

Чаще всего причина в том, что ссылку сравнивают со строкой или с синонимом перечисления. Сравнивать нужно с конкретным значением через ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или с параметром запроса, содержащим ссылку нужного типа.

Что вернёт ВЫБОР, если ни одно условие не выполнено и ИНАЧЕ не указано?

Поле получит значение NULL. Это редко бывает желаемым поведением: NULL влияет на последующие сравнения, группировки и соединения. Поэтому ветку ИНАЧЕ рекомендуется указывать всегда, даже с нейтральным значением вроде пустой строки или нуля.

Замедляет ли ВЫБОР выполнение запроса?

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

Итог

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

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