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

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

1С: ВЫБОР в запросе с несколькими условиями

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

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

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

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

Базовый синтаксис ВЫБОР с несколькими условиями

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

ВЫБОР

КОГДА Заказы.Сумма >= 100000

ТОГДА "Крупный"

КОГДА Заказы.Сумма >= 10000

ТОГДА "Средний"

ИНАЧЕ "Мелкий"

КОНЕЦ КАК КатегорияЗаказа

Здесь три ветки, но сработает только одна — первая, чьё условие истинно. Заказ на 150 000 попадёт в «Крупный», потому что первая проверка выполнится раньше второй. Если бы строки поменять местами и поставить проверку «>= 10000» первой, все крупные заказы ошибочно классифицировались бы как средние.

Порядок условий: почему срабатывает только первая истинная ветка

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

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

ВЫБОР

КОГДА РАЗНОСТЬДАТ(Долг.ДатаОплаты, &ТекущаяДата, ДЕНЬ) > 90

ТОГДА "Критическая просрочка"

КОГДА РАЗНОСТЬДАТ(Долг.ДатаОплаты, &ТекущаяДата, ДЕНЬ) > 30

ТОГДА "Просрочка"

КОГДА РАЗНОСТЬДАТ(Долг.ДатаОплаты, &ТекущаяДата, ДЕНЬ) > 0

ТОГДА "Небольшая задержка"

ИНАЧЕ "В срок"

КОНЕЦ КАК СтатусДолга

Если нарушить порядок и поставить проверку «> 0» первой, все просроченные долги получат статус «Небольшая задержка», а ветки с 30 и 90 днями станут недостижимым кодом. Такую ошибку сложно заметить на глаз — запрос выполнится без сообщений, но отчёт покажет неверные цифры.

Типичные ошибки
01
Общее условие стоит выше частного — частная ветка никогда не срабатывает, итоговые цифры искажены без каких-либо сообщений об ошибке
02
Ветки возвращают разные типы (строка в одной, число в другой) — поле получает составной тип и ломает сортировку, группировку или вывод в СКД
03
Нет ветки ИНАЧЕ — для части строк возвращается NULL, который затем «теряется» в итогах или сравнениях
04
Сравнение с NULL через знак равенства вместо ЕСТЬ NULL — условие никогда не будет истинным

Составные условия: И, ИЛИ и проверка нескольких полей

Условие внутри КОГДА не ограничено одним сравнением. Можно комбинировать несколько проверок через И и ИЛИ, обязательно расставляя скобки, чтобы приоритет операций был явным. Это нужно, когда категория зависит сразу от нескольких реквизитов — например, от вида документа и признака проведения.

ВЫБОР

КОГДА Реализация.Проведен

И Реализация.СуммаДокумента > 0

ТОГДА "Действующая"

КОГДА Реализация.Проведен

И Реализация.СуммаДокумента = 0

ТОГДА "Проведена без суммы"

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

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

ИНАЧЕ "Черновик"

КОНЕЦ КАК СостояниеДокумента

Обратите внимание на порядок: проверка пометки удаления стоит после проверок проведённости. Если документ одновременно проведён и помечен на удаление (такое встречается в реальных базах), приоритет отдаётся статусу «Действующая» или «Проведена без суммы». Какой приоритет правильный — решает бизнес-логика, а не язык запросов, поэтому порядок веток нужно согласовать с постановкой задачи.

Для перечислений удобно сравнивать поле со значением через ЗНАЧЕНИЕ(Перечисление.Статусы.Оплачен), а для проверки принадлежности списку — через оператор В: КОГДА Товар.Вид В (&СписокВидов). Это компактнее, чем цепочка ИЛИ.

ВЫБОР сравнения и вложенные конструкции

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

ВЫБОР Цены.ТипЦен

КОГДА ЗНАЧЕНИЕ(Справочник.ТипыЦен.Оптовая)

ТОГДА "Опт"

КОГДА ЗНАЧЕНИЕ(Справочник.ТипыЦен.Розничная)

ТОГДА "Розница"

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

КОНЕЦ КАК ВидЦены

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

Сравнение вариантов

Полная форма (КОГДА условие)

Подходит для диапазонов, составных условий с И/ИЛИ, проверок NULL и сравнений разных полей. Самый гибкий вариант.

Форма сравнения (ВЫБОР выражение КОГДА значение)

Подходит для перебора фиксированных значений одного поля: перечислений, кодов, типов. Короче, но работает только на равенство.

Соединение с таблицей соответствий

Подходит, когда пар «значение — результат» много или они меняются пользователями. Данные хранятся в справочнике или регистре, запрос остаётся простым.

Типизация результата и работа с NULL

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

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

Отдельная тема — NULL в условиях. Сравнение КОГДА Поле = NULL всегда ложно, даже если поле действительно пустое. Правильная проверка — КОГДА Поле ЕСТЬ NULL. Если поле может быть NULL из-за левого соединения, оберните его в ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) ещё до сравнения.

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

Надёжный способ убедиться, что многоусловный ВЫБОР работает правильно, — подобрать тестовые строки, попадающие в каждую ветку, и проверить результат по ним. Для этого удобно временно добавить в выборку сами проверяемые поля (сумму, дату, признаки), чтобы видеть, почему строка получила именно такое значение.

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

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

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

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

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

Маршрут решения

Как выбрать действие

Условий 2–5 и они фиксированы постановкой задачиИспользуйте ВЫБОР с ветками КОГДА, упорядоченными от частного к общему
Нужно расшифровать одно поле по списку фиксированных значенийИспользуйте краткую форму ВЫБОР выражение КОГДА значение
Пар «условие — результат» много или они должны меняться без доработки кодаВынесите соответствия в справочник или регистр сведений и соедините таблицы в запросе
ВЫБОР используется для фильтрации строкПеренесите логику в секцию ГДЕ с прямыми условиями И/ИЛИ — так работают индексы

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

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

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

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

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

Можно ли в ТОГДА вернуть значение другого поля, а не константу?

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

Как сравнить с пустой ссылкой внутри КОГДА?

Через ЗНАЧЕНИЕ с указанием типа, например: КОГДА Док.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка). Проверка ЕСТЬ NULL здесь не подойдёт — пустая ссылка и NULL в запросах 1С это разные состояния.

Есть ли ограничение на количество веток КОГДА?

Жёсткого документированного ограничения на число веток нет, но на практике конструкции с десятками условий трудно проверять и поддерживать. Если логика разрастается, переносите соответствия в данные (справочник или регистр сведений) и заменяйте ВЫБОР соединением.

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

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

Итог

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

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