Разработка и Конфигурация · 10 мин
ВЫБОР КОГДА в запросе 1С: как работает условный оператор выборки
Конструкция ВЫБОР КОГДА в запросах 1С: синтаксис, примеры аналога CASE, работа с NULL, типовые ошибки и оптимизация запросов для разработчиков.
Конструкция ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ — встроенный аналог оператора CASE в языке запросов 1С. Она позволяет прямо в тексте запроса вычислять значение поля по условию: подставлять текстовые расшифровки статусов, рассчитывать скидки по диапазонам, заменять NULL и формировать служебные признаки без постобработки в коде.
Использование ВЫБОР вместо разбора результата в цикле на встроенном языке сокращает объём кода и часто ускоряет выборку, потому что вся логика выполняется на стороне СУБД. При этом у конструкции есть ограничения по типам возвращаемых значений и нюансы с производительностью, которые важно учитывать на больших таблицах.
Синтаксис конструкции ВЫБОР КОГДА
Полная форма оператора выглядит так: после ключевого слова ВЫБОР перечисляются пары КОГДА условие ТОГДА значение, в конце — необязательная ветка ИНАЧЕ и обязательное слово КОНЕЦ. Условий КОГДА может быть сколько угодно, они проверяются последовательно сверху вниз.
ВЫБОР
КОГДА Продажи.Сумма >= 100000
ТОГДА "Крупная"
КОГДА Продажи.Сумма >= 10000
ТОГДА "Средняя"
ИНАЧЕ "Мелкая"
КОНЕЦ КАК КатегорияСделки
Если ни одно условие не выполнилось и ветка ИНАЧЕ отсутствует, поле получит значение NULL. Это частый источник ошибок: разработчик забывает ИНАЧЕ, а потом удивляется пустым значениям в отчёте. Поэтому правило простое — всегда явно указывайте ИНАЧЕ, даже если возвращаете пустую строку или ноль.
Простые условия и сравнение со ссылками
Чаще всего ВЫБОР применяют для расшифровки перечислений и статусов документов. Вместо того чтобы выводить ссылку на перечисление и потом преобразовывать её в представление, можно сразу вернуть понятный текст:
ВЫБОР
КОГДА Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.Новый)
ТОГДА "Ожидает обработки"
КОГДА Заказ.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказа.Закрыт)
ТОГДА "Выполнен"
ИНАЧЕ "В работе"
КОНЕЦ КАК СтатусТекстом
Обратите внимание: сравнивать ссылочные значения нужно с конкретными значениями, полученными через ЗНАЧЕНИЕ() или параметр запроса. Сравнение ссылки со строковым представлением («Закрыт») не сработает — условие просто никогда не будет истинным, и вы всегда попадёте в ветку ИНАЧЕ.
В условиях КОГДА допустимы любые логические выражения языка запросов: сравнения, проверка В ИЕРАРХИИ, ПОДОБНО, логические И/ИЛИ, вложенные ВЫБОР. Это позволяет строить довольно сложную логику без выхода в код.
Работа с NULL и замена пустых значений
Классический сценарий — левое соединение, после которого часть полей содержит NULL. Проверка на NULL внутри ВЫБОР выполняется через конструкцию ЕСТЬ NULL:
ВЫБОР
КОГДА Остатки.КоличествоОстаток ЕСТЬ NULL
ТОГДА 0
ИНАЧЕ Остатки.КоличествоОстаток
КОНЕЦ КАК Остаток
Для простой замены NULL удобнее функция ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) — она короче и читается легче. Но ВЫБОР гибче: через него можно проверить сразу несколько условий, например отдельно обработать NULL, ноль и отрицательные значения с разными результатами.
ВЫБОР в итогах, группировке и условиях соединения
Оператор ВЫБОР можно использовать не только в списке выбираемых полей. Он допустим в условиях ГДЕ, в соединениях таблиц, в группировках и внутри агрегатных функций. Типичный приём — выборочное суммирование:
СУММА(ВЫБОР
КОГДА Обороты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА Обороты.Количество
ИНАЧЕ 0
КОНЕЦ) КАК Приход
Такой приём позволяет одним запросом получить несколько колонок с разными условиями агрегации вместо нескольких запросов или свёртки таблицы в коде. Группировка по выражению ВЫБОР тоже работает: можно сгруппировать данные, например, по рассчитанной категории клиента.
В условиях соединения ВЫБОР используют реже, но он бывает полезен, когда ключ связи зависит от типа строки. Учтите, что соединение по вычисляемому выражению мешает СУБД использовать индексы, и на больших таблицах такой запрос может работать заметно медленнее.
Требования к типам возвращаемых значений
Все ветки ТОГДА и ИНАЧЕ должны возвращать значения совместимых типов. Строка в одной ветке и число в другой приведут к ошибке исполнения запроса. Если нужен смешанный результат, приведите значения к одному типу явно — например, число к строке через функцию представления или наоборот.
Отдельная тонкость — ссылочные типы. Если одна ветка возвращает ссылку на справочник «Номенклатура», а другая — на «Контрагенты», поле получит составной тип. Это допустимо, но усложнит дальнейшую обработку результата и может замедлить запрос. По возможности унифицируйте типы на этапе проектирования запроса.
Строки в разных ветках тоже стоит приводить к одинаковой длине через ВЫРАЗИТЬ(... КАК Строка(50)), иначе итоговый тип поля может получить неожиданную длину, что критично при помещении результата во временную таблицу с последующим соединением.
Производительность и порядок условий
Порядок веток КОГДА имеет двойное значение. Во-первых, логическое: проверка идёт сверху вниз, и первое истинное условие «перехватывает» строку. Если ветка «Сумма >= 10000» стоит выше, чем «Сумма >= 100000», крупные сделки никогда не попадут в свою категорию. Всегда располагайте более строгие условия выше.
Во-вторых, производительность: условия, отсекающие большинство строк, выгоднее ставить первыми, чтобы движок реже вычислял остальные ветки. На небольших выборках разница незаметна, но на миллионах записей порядок условий и отсутствие обращений к соединённым таблицам внутри ВЫБОР дают ощутимый выигрыш.
Если логика ВЫБОР разрастается до десятков веток, это сигнал перенести классификацию в данные: завести служебный реквизит или регистр сведений с соответствием и соединяться с ним вместо громоздкого условного оператора. Такой запрос проще поддерживать, и он работает быстрее.
- 1Определите, какое значение должно получиться в каждой ситуации, включая случай «ни одно условие не подошло»
- 2Запишите ветки КОГДА от самого строгого условия к самому общему
- 3Обязательно добавьте ИНАЧЕ с осмысленным значением по умолчанию
- 4Проверьте, что все ветки возвращают совместимые типы; при необходимости примените ВЫРАЗИТЬ
- 5Выполните запрос в консоли запросов на реальных данных и проверьте каждую категорию результата
- 6На больших таблицах замерьте время выполнения и при необходимости упростите условия или вынесите классификацию в данные
Проверка результата и отладка
Отлаживать ВЫБОР удобнее всего в консоли запросов: выведите рядом с вычисляемым полем исходные поля, участвующие в условиях. Так сразу видно, почему строка попала в конкретную ветку, и не «съело» ли верхнее условие строки, предназначенные для нижнего.
Дополнительный приём — временно добавить в выборку номер сработавшей ветки отдельным полем (числа 1, 2, 3 в ветках ТОГДА). После отладки это служебное поле удаляется. Такой способ быстро выявляет строки, уходящие в ИНАЧЕ из-за NULL в исходных данных.
Как проверить результат
Распределение соответствует ожиданиям по данным
Все строки попали в ИНАЧЕ — вероятно, условия не срабатывают
NULL отсутствуют или появляются только осознанно
NULL там, где ожидалось значение — забыта ветка ИНАЧЕ
Однородный тип во всех строках
Смешанные типы — ветки возвращают несовместимые значения
Сопоставимо с аналогичным запросом без ВЫБОР
Кратный рост времени — условия обращаются к соединённым таблицам или отключили индексы
Часто задаваемые вопросы
Чем ВЫБОР КОГДА отличается от функции ЕСТЬNULL?
ЕСТЬNULL решает одну задачу — подставляет значение вместо NULL. ВЫБОР КОГДА проверяет произвольные условия и возвращает разные значения для разных ситуаций. Для простой замены NULL используйте ЕСТЬNULL — она короче; для классификации по нескольким условиям нужен ВЫБОР.
Можно ли вкладывать один ВЫБОР внутрь другого?
Да, вложенные ВЫБОР допустимы и в условиях, и в возвращаемых значениях. Практический предел — читаемость: при более чем двух уровнях вложенности запрос становится трудно сопровождать, и логику лучше разбить на несколько полей или перенести во временную таблицу.
Работает ли ВЫБОР в секции ИТОГИ и при группировке?
Да. Выражение ВЫБОР можно указывать в полях группировки, тогда строки будут сгруппированы по вычисленному значению. Также ВЫБОР допустим внутри агрегатных функций, что позволяет суммировать только строки, удовлетворяющие условию.
Почему условие с перечислением никогда не срабатывает?
Чаще всего причина в том, что ссылку сравнивают со строкой или с синонимом перечисления. Сравнивать нужно с конкретным значением через ЗНАЧЕНИЕ(Перечисление.Имя.Значение) или с параметром запроса, содержащим ссылку нужного типа.
Что вернёт ВЫБОР, если ни одно условие не выполнено и ИНАЧЕ не указано?
Поле получит значение NULL. Это редко бывает желаемым поведением: NULL влияет на последующие сравнения, группировки и соединения. Поэтому ветку ИНАЧЕ рекомендуется указывать всегда, даже с нейтральным значением вроде пустой строки или нуля.
Замедляет ли ВЫБОР выполнение запроса?
Сам по себе в списке выбираемых полей — незначительно. Заметное замедление возникает, когда ВЫБОР используется в условиях соединения или отбора на больших таблицах, либо когда внутри условий идёт обращение к полям соединённых таблиц. В таких случаях проверяйте план запроса и рассматривайте перенос классификации в данные.
Что важно запомнить
ВЫБОР КОГДА проверяет условия сверху вниз и возвращает значение первой истинной ветки. Всегда указывайте ИНАЧЕ, следите за совместимостью типов во всех ветках, проверяйте NULL только через ЕСТЬ NULL и располагайте строгие условия выше общих. В условиях соединений и отборов на больших таблицах применяйте ВЫБОР с осторожностью и контролируйте время выполнения.