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