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