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

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

Конструкция ВЫБОР КОГДА в запросе 1С

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

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

Типичная задача: в отчёте по документам нужно вывести текстовый статус («Проведён», «Помечен на удаление», «Черновик») вместо хранимых булевых признаков. Решать её кодом после получения результата — лишний проход по данным и лишний расход памяти. Конструкция ВЫБОР решает это одним выражением в тексте запроса.

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

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

Базовая форма выглядит так:

ВЫБОР

КОГДА Документ.Проведен

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

КОГДА Документ.ПометкаУдаления

ТОГДА "Помечен на удаление"

ИНАЧЕ

"Черновик"

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

Ключевые правила синтаксиса:

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

Существует и краткая форма — «простой ВЫБОР», где сравнивается одно выражение со списком значений:

ВЫБОР Документ.ВидОперации

КОГДА ЗНАЧЕНИЕ(Перечисление.ВидыОпераций.Продажа)

ТОГДА "Реализация"

КОГДА ЗНАЧЕНИЕ(Перечисление.ВидыОпераций.Возврат)

ТОГДА "Возврат"

ИНАЧЕ "Прочее"

КОНЕЦ

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

Порядок проверки условий и роль ветки ИНАЧЕ

Условия КОГДА вычисляются строго сверху вниз. Как только одно из них истинно, возвращается соответствующее значение ТОГДА, а остальные ветки не проверяются. Поэтому порядок условий имеет значение, когда диапазоны пересекаются.

Пример с пересекающимися диапазонами:

ВЫБОР

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

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

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

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

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

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

Если поменять первые две ветки местами, все суммы от 10 000 попадут в «Средняя», и ветка «Крупная» никогда не сработает. Правило простое: более строгие (узкие) условия ставьте выше.

Отдельно стоит помнить про NULL. Если поле в условии равно NULL (например, из-за левого соединения без совпадения), то любое сравнение с ним даёт не ИСТИНА и не ЛОЖЬ, а неопределённость — ветка не сработает. Строка с NULL уйдёт в ИНАЧЕ, а если ИНАЧЕ нет — результатом будет NULL. Для надёжности комбинируйте ВЫБОР с ЕСТЬNULL():

ВЫБОР

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

ТОГДА "В наличии"

ИНАЧЕ "Нет на складе"

КОНЕЦ

Типы значений в ветках ТОГДА и ИНАЧЕ

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

Безопасные комбинации:

  • строки разной длины — итоговый тип строка;
  • числа с разной точностью — итоговый тип число;
  • ссылки на разные типы объектов — допустимо, поле станет составного типа, но в СКД такое поле может быть недоступно для некоторых операций;
  • NULL через ЗНАЧЕНИЕ(...) с пустой ссылкой нужного типа вместо литерала NULL.

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

ВЫБОР

КОГДА Заказы.Ответственный ЕСТЬ NULL

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

ИНАЧЕ Заказы.Ответственный

КОНЕЦ КАК Менеджер

Явное приведение типа через ВЫРАЗИТЬ(... КАК ...) внутри веток помогает, когда платформа не может сама вывести единый тип, например при смешении строки неограниченной длины и строки фиксированной длины.

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

Практические сценарии использования

Расчётный показатель в отчёте

Классическая задача — вычислить признак или коэффициент, которого нет в данных. Например, наценка в процентах с защитой от деления на ноль:

ВЫБОР

КОГДА Продажи.Себестоимость = 0

ТОГДА 0

ИНАЧЕ ВЫРАЗИТЬ((Продажи.Сумма - Продажи.Себестоимость) / Продажи.Себестоимость * 100 КАК ЧИСЛО(10, 2))

КОНЕЦ КАК НаценкаПроцент

Обратите внимание: проверка делителя на ноль должна идти первой веткой, иначе запрос завершится ошибкой деления на ноль ещё до возврата результата.

Замена значения для группировки

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

Условия в соединениях и секции ГДЕ

Конструкция допустима не только в списке полей. В условии соединения или в ГДЕ она позволяет гибко подставлять значение сравнения:

ГДЕ Продажи.Склад = ВЫБОР

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

ТОГДА Продажи.Склад

ИНАЧЕ &Склад

КОНЕЦ

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

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

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

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

Основные ограничения, о которых стоит помнить:

  • ВЫБОР нельзя использовать в секции ИТОГИ как агрегатную функцию — сначала вычислите поле, потом суммируйте;
  • в иерархических итогах и при группировке выражение должно быть доступно на уровне группировки;
  • условие КОГДА не может содержать агрегатные функции напрямую — они допустимы только в ИМЕЮЩИЕ после группировки;
  • чрезмерное число веток (десятки) ухудшает читаемость; если значений много, рассмотрите соединение с таблицей соответствий или виртуальной таблицей вместо громоздкого ВЫБОР.
Если логика ВЫБОР повторяется в нескольких запросах конфигурации, вынесите её в отдельный временный запрос с виртуальной таблицей соответствий или зафиксируйте в одном месте пакета запроса. Так проще поддерживать: изменение правила не потребует правки десятка текстов запросов.
ПЗ
Практическое замечание

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

Проверять конструкцию удобнее всего в консоли запросов (в типовых конфигурациях есть встроенная, либо используется внешняя обработка консоли). Выведите рядом вычисляемое поле и исходные поля, участвующие в условии, — так сразу видно, почему сработала та или иная ветка.

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

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

Значения вычисляемого поля
Норма

Каждая строка получила ожидаемое значение одной из веток

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

Встречаются NULL или значения из неправильной ветки

Тип поля в СКД/таблице значений
Норма

Единый тип, поле доступно для отбора и группировки

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

Составной или неопределённый тип, поле недоступно в настройках

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

Обработаны через ЕСТЬNULL или попали в осознанную ветку ИНАЧЕ

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

Молча ушли в ИНАЧЕ и исказили итоги

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

Сопоставимо с запросом без ВЫБОР

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

Резкий рост из-за разыменований или подзапросов внутри условий

Если результат неожиданный, первым делом проверьте три вещи: порядок веток, наличие NULL в исходных данных и точное соответствие типов сравниваемых значений (например, ссылка на перечисление против строки). Эти три причины покрывают подавляющее большинство «странных» результатов.

Итог

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

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

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

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

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

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

Да, конструкция допустима в ГДЕ, в условиях соединений и в ИМЕЮЩИЕ. Типичный приём — подстановка необязательного параметра отбора. Но учитывайте, что ВЫБОР в ГДЕ может мешать оптимизатору СУБД использовать индексы, поэтому в динамических списках и СКД лучше использовать штатные отборы.

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

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

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

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

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

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

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

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