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