ВЫБОР КОГДА … ИНАЧЕ … КОНЕЦ: условные поля в языке запросов 1С

· 10 мин

Содержание

В языке запросов 1С «Когда Иначе» записывается так: ВЫБОР КОГДА <условие> ТОГДА <значение> ИНАЧЕ <значение> КОНЕЦ. Условия проверяются сверху вниз, срабатывает первое истинное, а если ни одно не подошло — берётся значение после ИНАЧЕ. Нет ИНАЧЕ — результат будет NULL.

Это аналог CASE WHEN … THEN … ELSE … END из SQL, и в английском синтаксисе 1С он пишется именно так. Оператор работает в списке полей, в ГДЕ, УПОРЯДОЧИТЬ ПО, ИМЕЮЩИЕ, в условиях соединения и внутри агрегатных функций. Синтаксис одинаков для любой конфигурации на платформе 8.3: БП, ЗУП, УТ, ERP или своей разработки.

Синтаксис ВЫБОР КОГДА ТОГДА ИНАЧЕ КОНЕЦ

Полная форма оператора:

ВЫБОР
    КОГДА <условие 1> ТОГДА <выражение 1>
    КОГДА <условие 2> ТОГДА <выражение 2>
    ИНАЧЕ <выражение по умолчанию>
КОНЕЦ КАК ИмяПоля

Что из чего состоит:

  • 🔹 ВЫБОР открывает конструкцию, КОНЕЦ закрывает. Забытый КОНЕЦ — самая частая синтаксическая ошибка.
  • 🔹 КОГДА … ТОГДА — пара «условие → результат». Пар может быть сколько угодно, но хотя бы одна обязательна.
  • 🔹 ИНАЧЕ — необязательная ветка по умолчанию.
  • 🔹 КАК ИмяПоля — псевдоним. Без него платформа назовёт поле сама, и обращаться к нему из кода будет неудобно.

Простой пример: разбить номенклатуру на услуги и товары.

ВЫБРАТЬ
    Номенклатура.Наименование КАК Наименование,
    ВЫБОР
        КОГДА Номенклатура.Услуга ТОГДА "Услуга"
        ИНАЧЕ "Товар"
    КОНЕЦ КАК Вид
ИЗ
    Справочник.Номенклатура КАК Номенклатура

В 1С есть только «поисковая» форма оператора — с полноценным условием после каждого КОГДА. Короткая запись из SQL вида ВЫБОР Поле КОГДА 1 ТОГДА … не поддерживается. Сравнение пишут явно: КОГДА Поле = 1 ТОГДА ….

После КОГДА допустимо любое логическое выражение языка запросов: сравнения, И, ИЛИ, НЕ, В (…), МЕЖДУ, ПОДОБНО, ЕСТЬ NULL, ССЫЛКА, а также параметры &Имя.

Как вставить конструкцию в текст запроса из кода

В модуле текст запроса — это строка. Строковые литералы внутри неё пишут в удвоенных кавычках:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Товары.Номенклатура,
|    ВЫБОР
|        КОГДА Товары.Сумма >= &Порог ТОГДА ""Крупная""
|        ИНАЧЕ ""Обычная""
|    КОНЕЦ КАК КатегорияСтроки
|ИЗ
|    Документ.РеализацияТоваровУслуг.Товары КАК Товары";
Запрос.УстановитьПараметр("Порог", 100000);

В конструкторе запроса такое поле добавляют как произвольное выражение: открывают редактор выражения поля и вписывают ВЫБОР … КОНЕЦ целиком. Конструктор его сохранит и потом откроет без потерь.

Несколько условий КОГДА и вложенный ВЫБОР

Когда вариантов больше двух, просто добавляйте строки КОГДА. Порядок решает всё: платформа остановится на первом истинном условии.

ВЫБОР
    КОГДА Остатки.КоличествоОстаток <= 0 ТОГДА "Нет в наличии"
    КОГДА Остатки.КоличествоОстаток < 10 ТОГДА "Мало"
    КОГДА Остатки.КоличествоОстаток < 100 ТОГДА "Достаточно"
    ИНАЧЕ "Много"
КОНЕЦ КАК УровеньЗапаса

Проверим на числах. Остаток 5: первое условие ложно, второе истинно — «Мало». Остаток 50 — «Достаточно». Остаток 250 — «Много». Если поменять местами строки «< 100» и «< 10», остаток 5 попадёт в «Достаточно», и ветка «Мало» не сработает никогда.

Ставьте узкие условия выше широких. Иначе часть веток станет мёртвым кодом, а ошибку не покажет ни синтаксис-контроль, ни конструктор.

Комбинированные условия

В одном КОГДА можно проверять несколько полей сразу:

ВЫБОР
    КОГДА Продажи.Сумма > 500000 И Продажи.Контрагент.ЮрФизЛицо = ЗНАЧЕНИЕ(Перечисление.ЮрФизЛицо.ЮрЛицо)
        ТОГДА "Ключевой клиент"
    КОГДА Продажи.Сумма > 500000
        ТОГДА "Крупный покупатель"
    ИНАЧЕ "Розница"
КОНЕЦ

Предопределённые значения и перечисления в условиях берут через ЗНАЧЕНИЕ(…). Строку вроде "ЮрЛицо" с перечислением сравнивать бесполезно — условие не выполнится.

Вложенный ВЫБОР

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

ВЫБОР
    КОГДА Документ.Проведен ТОГДА
        ВЫБОР
            КОГДА Документ.СуммаДокумента = 0 ТОГДА "Проведён, пустой"
            ИНАЧЕ "Проведён"
        КОНЕЦ
    ИНАЧЕ "Черновик"
КОНЕЦ КАК Состояние

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

«Когда Иначе» внутри СУММА, КОЛИЧЕСТВО и других агрегатов

Самый полезный приём — условная агрегация. Один проход по таблице даёт несколько итогов в разных колонках, без подзапросов и ОБЪЕДИНИТЬ.

ВЫБРАТЬ
    Движения.Номенклатура,
    СУММА(ВЫБОР
        КОГДА Движения.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
            ТОГДА Движения.Количество
        ИНАЧЕ 0
    КОНЕЦ) КАК Поступило,
    СУММА(ВЫБОР
        КОГДА Движения.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход)
            ТОГДА Движения.Количество
        ИНАЧЕ 0
    КОНЕЦ) КАК Списано
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК Движения
СГРУППИРОВАТЬ ПО
    Движения.Номенклатура

Имя регистра здесь условное — подставьте регистр своей конфигурации. Пример: у товара приход 30 и 20 штук, расход 15. Получим строку «Поступило 50, Списано 15».

ИНАЧЕ 0 или без ИНАЧЕ

Для СУММА разница почти незаметна: агрегатные функции пропускают NULL. Но есть нюанс. Если ни одна строка группы не попала в ветку, СУММА без ИНАЧЕ 0 вернёт NULL, а не ноль. В отчёте будет пустая ячейка, а в коде — сравнение с NULL, которое ломает арифметику.

С КОЛИЧЕСТВО всё наоборот — там ИНАЧЕ обычно мешает:

КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР
    КОГДА Продажи.Сумма > 100000 ТОГДА Продажи.Контрагент
КОНЕЦ) КАК КрупныхПокупателей

Строки, не прошедшие условие, дают NULL, и КОЛИЧЕСТВО их не считает. Если дописать ИНАЧЕ 0, ноль станет ещё одним «различным» значением и прибавит единицу к результату.

Группировка по полю с ВЫБОР

Если поле с ВЫБОР стоит в списке выборки без агрегата, а в запросе есть СГРУППИРОВАТЬ ПО, платформа требует, чтобы его источник входил в группировку. Иначе получите ошибку вида «Поле не входит в группу».

Два рабочих варианта:

  1. Сгруппировать по исходным полям, которые участвуют в условии, например СГРУППИРОВАТЬ ПО Остатки.Номенклатура, Остатки.КоличествоОстаток.
  2. Повторить в СГРУППИРОВАТЬ ПО выражение ВЫБОР … КОНЕЦ целиком, символ в символ. Псевдоним из ВЫБРАТЬ в группировке не работает .

Если нужен итог именно по категориям («сколько продаж в каждой категории»), удобнее посчитать категорию во временной таблице, а сгруппировать уже во втором запросе пакета по готовому полю.

Где ещё работает конструкция: таблица вариантов

Часть запросаДля чегоПример
ВЫБРАТЬВычисляемое поле, подпись, флагВЫБОР КОГДА Сумма > 0 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК ЕстьСумма
Агрегатная функцияИтоги по условию в отдельных колонкахСУММА(ВЫБОР КОГДА … ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ)
ГДЕУсловие, зависящее от параметраГДЕ ВЫБОР КОГДА &ВсеСклады ТОГДА ИСТИНА ИНАЧЕ Склад = &Склад КОНЕЦ
УПОРЯДОЧИТЬ ПОСвой порядок сортировкиУПОРЯДОЧИТЬ ПО ВЫБОР КОГДА Статус = &Срочный ТОГДА 1 ИНАЧЕ 2 КОНЕЦ
ИМЕЮЩИЕФильтр по итогу с условиемИМЕЮЩИЕ СУММА(ВЫБОР КОГДА … ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) > 3
СГРУППИРОВАТЬ ПОГруппировка по вычисленной категорииВыражение ВЫБОР … КОНЕЦ целиком
Условие СОЕДИНЕНИЕСоединение по разным полям в зависимости от типаРаботает, но медленно — см. раздел про оптимизацию

Флаг Истина/Ложь в выборке

Логическое выражение вроде Сумма > 0 нельзя поставить в список полей напрямую. Стандартный приём — обернуть его в ВЫБОР:

ВЫБОР КОГДА Товары.Сумма > 0 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК ЕстьСумма

Поле получит тип «Булево», и в коде с ним можно работать как с обычным флагом.

Своя сортировка

Сортировать по алфавиту или по дате умеет любой запрос. А если «Срочные» нужны вверху, «Обычные» — в середине, а «Отложенные» — внизу, помогает ВЫБОР с числовыми весами 1, 2, 3 в УПОРЯДОЧИТЬ ПО. Поле с весом даже не обязательно выводить в результат.

NULL, ссылки и тип результата

Проверка на NULL

NULL появляется после левых соединений и при обращении к реквизитам через точку у пустой ссылки. Сравнение Поле = NULL никогда не бывает истинным — правильно писать Поле ЕСТЬ NULL:

ВЫБОР
    КОГДА Цены.Цена ЕСТЬ NULL ТОГДА 0
    ИНАЧЕ Цены.Цена
КОНЕЦ КАК Цена

Для такой простой подстановки короче функция ЕСТЬNULL(Цены.Цена, 0). Результат тот же, текст запроса чище. ВЫБОР нужен, когда при NULL надо вернуть не константу, а другое поле или выполнить ещё проверку.

Любое условие с участием NULL (кроме ЕСТЬ NULL) считается невыполненным. Строка с пустой ценой пройдёт мимо КОГДА Цена > 100 и мимо КОГДА Цена <= 100, а попадёт в ИНАЧЕ. Об этом легко забыть, когда кажется, что условия «покрывают все случаи».

Составные типы и оператор ССЫЛКА

Поле Регистратор или реквизит составного типа удобно разбирать по видам документов:

ВЫБОР
    КОГДА Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
        ТОГДА "Поступление"
    КОГДА Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
        ТОГДА "Реализация"
    ИНАЧЕ "Прочее"
КОНЕЦ КАК ВидОперации

Чтобы достать реквизит конкретного вида, добавьте ВЫРАЗИТЬ: ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент. Без него платформа соединит таблицы всех возможных типов регистратора, а это ощутимо медленнее.

Какой тип вернёт ВЫБОР

Тип поля складывается из типов всех веток. Если в одной ветке строка, а в другой число, поле станет составным «Строка, Число». С таким полем неудобно работать: его нельзя сразу просуммировать, сортировка и сравнение ведут себя неочевидно.

  • ✅ Возвращайте во всех ветках один тип: везде числа или везде строки.
  • ✅ Если ветка должна дать «пусто», используйте пустое значение того же типа: 0, "", ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка).
  • ✅ Для строк задайте длину явно, если результат потом сравнивается или участвует в группировке: ВЫРАЗИТЬ(ВЫБОР … КОНЕЦ КАК СТРОКА(50)).

Строки неограниченной длины нельзя сравнивать, группировать и использовать в РАЗЛИЧНЫЕ. Если в ветку ТОГДА попадает реквизит типа «Строка» без ограничения длины (например, комментарий), оберните его в ВЫРАЗИТЬ(… КАК СТРОКА(N)).

Скорость: когда ВЫБОР тормозит запрос и чем его заменить

В списке полей ВЫБОР почти ничего не стоит: СУБД считает выражение для уже отобранных строк. Проблемы начинаются, когда он попадает в отбор или соединение.

ВЫБОР в ГДЕ и в условии соединения

Условие вида ГДЕ ВЫБОР КОГДА … КОНЕЦ = … СУБД не может разложить на индексный поиск. Она вычисляет выражение для каждой строки таблицы, то есть читает таблицу целиком. На справочнике в 500 элементов этого не видно. На регистре в несколько миллионов записей запрос вырастает с долей секунды до минут.

Что делать вместо этого:

ЗадачаВместо ВЫБОРПочему лучше
Отбор «все склады или один»Два варианта текста запроса, собранные в коде, или ГДЕ (&ВсеСклады ИЛИ Склад = &Склад)Условие проще, оптимизатору понятнее
Соединение по разным полям в зависимости от типаДва запроса с ОБЪЕДИНИТЬ ВСЕ, в каждом своё простое соединениеКаждое соединение идёт по индексу
Подстановка значения вместо NULLЕСТЬNULL(Поле, 0)Короче, тот же результат
Десятки веток «код → название»Временная таблица соответствий и соединение с нейСправочник правил можно менять без правки запроса
Отбор по периоду виртуальной таблицыПараметры виртуальной таблицы (&Период, Условие)Отбор выполнится до расчёта остатков, а не после

Чего не стоит делать

  • ❌ Вычислять в запросе ВЫБОР по полю, которое затем стоит в ГДЕ того же запроса. Сначала отберите строки по исходному полю, потом классифицируйте.
  • ❌ Ставить ВЫБОР в условия виртуальной таблицы регистра. Там нужны простые условия на измерения.
  • ❌ Разворачивать в запросе логику, которую проще посчитать в СКД. В системе компоновки данных ВЫБОР тоже доступен в вычисляемых полях и выражениях ресурсов, и считается уже над результатом.

Чтобы проверить, мешает ли ВЫБОР, сравните время выполнения запроса в консоли запросов с конструкцией в ГДЕ и с переписанным условием на реальном объёме данных. Тестовая база с сотней документов разницы не покажет.

Проверьте себя
Что вернёт ВЫБОР КОГДА Количество > 10 ТОГДА "Много" КОНЕЦ при Количество = 3?
Как правильно проверить пустое значение после левого соединения?
Что посчитает КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР КОГДА Сумма > 0 ТОГДА Контрагент ИНАЧЕ 0 КОНЕЦ)?

Частые ошибки в конструкции «Когда Иначе»

Диагностика: выберите симптом

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

Можно ли использовать псевдоним поля из ВЫБОР в ГДЕ того же запроса?
Нет. Псевдоним из списка выборки в ГДЕ и СГРУППИРОВАТЬ ПО не виден. Повторите выражение целиком или вынесите расчёт во временную таблицу и отбирайте во втором запросе пакета.
Сколько условий КОГДА допускается в одной конструкции?
Жёсткого предела на практике не встречается, но десятки веток плохо читаются и сопровождаются. При большом числе соответствий удобнее временная таблица и соединение с ней.
Есть ли в языке запросов 1С функция IIF или аналог тернарного оператора?
Отдельной функции нет. Короткое условие пишут той же конструкцией в одну строку: ВЫБОР КОГДА Условие ТОГДА А ИНАЧЕ Б КОНЕЦ.
Можно ли писать конструкцию на английском?
Да. CASE WHEN … THEN … ELSE … END работает так же, как ВЫБОР КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ. Смешивать языки в одном тексте запроса можно, но читать такой код неудобно.
Можно ли вернуть из ветки ссылку на справочник?
Да, ветки могут возвращать ссылки, поля и параметры. Следите, чтобы все ветки давали ссылку одного вида, иначе поле получит составной тип.