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