Работа с условной логикой в запросах 1С:Предприятие 8.3 часто становится камнем преткновения для разработчиков. Оператор WHEN — один из самых мощных инструментов языка запросов, позволяющий реализовывать сложные условия прямо в SQL-подобных конструкциях без необходимости постобработки на встроенном языке. Однако его синтаксис и особенности применения вызывает вопросы даже у опытных программистов.

В этой статье мы разберём не только базовый синтаксис WHEN...THEN...ELSE, но и нюансы использования в связке с CASE, агрегатными функциями, подзапросами. Особое внимание уделим типичным ошибкам, которые приводят к некорректным результатам или падению производительности. Вы узнаете, как оптимизировать запросы с множественными условиями, избегать "ловушек" при работе с NULL-значениями в условной логике и применять WHEN для динамического формирования выходных данных.

Материал будет полезен как начинающим разработчикам, которые только осваивают язык запросов, так и опытным специалистам, стремящимся писать более эффективный и читаемый код. Все примеры приведены для актуальной версии платформы 1С:Предприятие 8.3.23 и выше, с учётом последних изменений в обработке условных выражений.

Базовый синтаксис оператора WHEN в 1С 8.3

Оператор WHEN в языке запросов используется для реализации условной логики прямо в тексте запроса. Он всегда работает в паре с THEN и необязательным ELSE, формируя конструкцию, аналогичную оператору Если...Тогда...Иначе во встроенном языке.

Общий вид конструкции:

ВЫБРАТЬ

ВЫРАЖЕНИЕ1 КАК Поле1,

ВЫБОР

КОГДА Условие1 ТОГДА Значение1

КОГДА Условие2 ТОГДА Значение2

...

ИНАЧЕ ЗначениеПоУмолчанию

КОНЕЦ КАК Поле2

ИЗ

Таблица

Ключевые особенности синтаксиса:

  • 🔹 Каждое условие КОГДА должно заканчиваться ТОГДА с указанием возвращаемого значения
  • 🔹 Блок ИНАЧЕ обязателен, если нужно обработать все возможные случаи (в противном случае для несоответствующих условий вернётся NULL)
  • 🔹 В одном выражении ВЫБОР можно использовать неограниченное количество КОГДА блоков
  • 🔹 Условия проверяются последовательно, и выполняется только первое истинное

Простейший пример с категоризацией клиентов по сумме заказов:

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

ВЫБОР

КОГДА СУММА(Заказы.СуммаДокумента) > 1000000 ТОГДА "VIP"

КОГДА СУММА(Заказы.СуммаДокумента) > 500000 ТОГДА "Премиум"

КОГДА СУММА(Заказы.СуммаДокумента) > 100000 ТОГДА "Стандарт"

ИНАЧЕ "Базовый"

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

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Наименование

📊 Как часто вы используете WHEN в запросах 1С?
Постоянно, в большинстве запросов
Иногда, для сложной логики
Редеко, предпочитаю обрабатывать данные после запроса
Никогда не использовал

WHEN vs CASE: в чём разница и когда что применять

Многие разработчики путают конструкции WHEN и CASE, хотя на самом деле WHEN является частью CASE. В языке запросов 1С существует два варианта записи условных выражений:

1. Простое условное выражение (без ключевого слова CASE):

ВЫБРАТЬ

ВЫРАЖЕНИЕ КАК Поле,

ВЫБОР

КОГДА Условие1 ТОГДА Значение1

КОГДА Условие2 ТОГДА Значение2

КОНЕЦ КАК Результат

2. Полная форма с CASE (аналогична стандартному SQL):

ВЫБРАТЬ

ВЫРАЖЕНИЕ КАК Поле,

CASE

WHEN Условие1 THEN Значение1

WHEN Условие2 THEN Значение2

ELSE ЗначениеПоУмолчанию

END КАК Результат

Разница между ними чисто синтаксическая — функциональность идентична. Однако есть нюансы:

Критерий WHEN (без CASE) CASE WHEN
Совместимость Только 1С Стандарт SQL, работает и в других СУБД
Читаемость Привычнее для 1С-разработчиков Универсальнее для специалистов, знающих SQL
Поддержка в старых версиях Доступно с 8.2 Требует 8.3.6+ для полной поддержки
Использование в подзапросах Без ограничений Может вызывать ошибки в сложных конструкциях

Практический совет: если вы пишете запрос, который потом может использоваться за пределами 1С (например, в внешних отчётах с прямым SQL), лучше использовать CASE WHEN. Для внутренних нужд системы удобнее привычный синтаксис с ВЫБОР...КОГДА.

💡

При отладке сложных условий с WHEN используйте конструкцию ВЫРАЗИТЬ(Условие КАК СТРОКА) в отдельном поле запроса — это поможет увидеть, какие именно условия срабатывают для каждой строки.

Практические примеры использования WHEN в реальных задачах

Рассмотрим типичные сценарии, где оператор WHEN становится незаменимым инструментом.

1. Динамическое формирование наименований

Частая задача — создание "умных" наименований, которые изменяются в зависимости от статуса или свойств объекта:

ВЫБРАТЬ

Документы.Номер КАК Номер,

Документы.Дата КАК Дата,

ВЫБОР

КОГДА Документы.ПометкаУдаления = ИСТИНА ТОГДА "[УДАЛЕН] " + Документы.Наименование

КОГДА Документы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДокументов.Одобрен) ТОГДА "✓ " + Документы.Наименование

КОГДА Документы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДокументов.НаУтверждении) ТОГДА "? " + Документы.Наименование

ИНАЧЕ Документы.Наименование

КОНЕЦ КАК ПолноеНаименование

ИЗ

Документ.РеализацияТоваровУслуг КАК Документы

2. Расчёт бонусов по сложным правилам

WHEN идеально подходит для реализации многоуровневых систем скидок или бонусов:

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

СУММА(Заказы.СуммаДокумента) КАК ОбщаяСумма,

ВЫБОР

КОГДА СУММА(Заказы.СуммаДокумента) > 1000000 ТОГДА СУММА(Заказы.СуммаДокумента) * 0.1

КОГДА СУММА(Заказы.СуммаДокумента) > 500000 ТОГДА СУММА(Заказы.СуммаДокумента) * 0.05

КОГДА Клиенты.ДатаРегистрации < ДОБАВИТЬКДАТЕ(ТЕКУЩАЯДАТА(), ГОД, -1) ТОГДА 5000

ИНАЧЕ 0

КОНЕЦ КАК БонусныеБаллы

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Наименование,

Клиенты.ДатаРегистрации

3. Фильтрация данных по сложным критериям

WHEN можно использовать прямо в секции WHERE для создания гибких фильтров:

ВЫБРАТЬ

Номенклатура.Наименование КАК Товар,

Остатки.КоличествоОстаток КАК Остаток

ИЗ

Справочник.Номенклатура КАК Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО Номенклатура.Ссылка = Остатки.Номенклатура

ГДЕ

ВЫБОР

КОГДА &ПоказыватьТолькоДефицит ТОГДА Остатки.КоличествоОстаток < 0

КОГДА &ПоказыватьТолькоИзбыток ТОГДА Остатки.КоличествоОстаток > 100

ИНАЧЕ ИСТИНА

КОНЕЦ

Проверены все возможные условия (нет "дыр" в логике)|Учтена обработка NULL-значений|Оптимизированы повторяющиеся вычисления в условиях|Тестировались пограничные случаи (нулевые значения, пустые строки)|-->

Типичные ошибки при работе с WHEN и как их избегать

Даже опытные разработчики допускают ошибки при работе с условной логикой в запросах. Вот наиболее распространённые проблемы и способы их решения:

1. Пропущенный блок ИНАЧЕ

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

// Плохо - может вернуть NULL

ВЫБОР

КОГДА Сумма > 1000 ТОГДА "Крупный"

КОГДА Сумма > 100 ТОГДА "Средний"

КОНЕЦ КАК ТипЗаказа

// Хорошо - всегда возвращает строку

ВЫБОР

КОГДА Сумма > 1000 ТОГДА "Крупный"

КОГДА Сумма > 100 ТОГДА "Средний"

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

КОНЕЦ КАК ТипЗаказа

2. Неправильная обработка NULL

Сравнения с NULL всегда возвращают UNKNOWN (неопределённость), что ломает логику WHEN:

// Это условие НИКОГДА не сработает для NULL

КОГДА Поле = NULL ТОГДА "Пустое"

// Правильный вариант

КОГДА Поле ЕСТЬ NULL ТОГДА "Пустое"

3. Избыточные вычисления в условиях

Если в нескольких условиях используется одно и то же сложное выражение, оно будет вычисляться многократно:

// Неэффективно - СУММА вычисляется 3 раза

ВЫБОР

КОГДА СУММА(Заказы.Сумма) > 1000000 ТОГДА "VIP"

КОГДА СУММА(Заказы.Сумма) > 500000 ТОГДА "Премиум"

ИНАЧЕ "Стандарт"

КОНЕЦ

// Оптимально - вынести в отдельное поле

ВЫБРАТЬ

СУММА(Заказы.Сумма) КАК ОбщаяСумма,

ВЫБОР

КОГДА ОбщаяСумма > 1000000 ТОГДА "VIP"

КОГДА ОбщаяСумма > 500000 ТОГДА "Премиум"

ИНАЧЕ "Стандарт"

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

4. Неучтённая последовательность проверок

Условия проверяются сверху вниз, и если первое условие истинно, остальные не выполняются:

// Ошибка - "Средний" заказы никогда не попадут в эту категорию

ВЫБОР

КОГДА Сумма > 100 ТОГДА "Большой" // Сначала проверяется это

КОГДА Сумма > 1000 ТОГДА "Очень большой" // А это уже никогда не сработает

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

КОНЕЦ

// Правильно - условия должны идти от более строгих к менее строгим

ВЫБОР

КОГДА Сумма > 1000 ТОГДА "Очень большой"

КОГДА Сумма > 100 ТОГДА "Большой"

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

КОНЕЦ

Почему WHEN может тормозить запрос?

Сложные условия в WHEN заставляют СУБД строить полные планы выполнения для каждой ветки. Особенно критично это при использовании подзапросов в условиях. Для оптимизации выносите повторяющиеся вычисления в отдельные поля или используйте временные таблицы для промежуточных результатов.

WHEN в связке с агрегатными функциями и группировкой

Особенно мощно WHEN проявляет себя при работе с агрегатными функциями и группировкой данных. Это позволяет создавать сложные аналитические отчёты прямо в одном запросе.

Пример 1: Условная агрегация

Подсчёт количества заказов по категориям прямо в запросе:

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

СУММА(ВЫБОР

КОГДА Заказы.СуммаДокумента > 100000 ТОГДА 1

ИНАЧЕ 0

КОНЕЦ) КАК КоличествоКрупныхЗаказов,

СУММА(ВЫБОР

КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Отменен) ТОГДА 1

ИНАЧЕ 0

КОНЕЦ) КАК КоличествоОтмененныхЗаказов

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Наименование

Пример 2: Динамическая группировка

Группировка данных по разным критериям в зависимости от параметра:

ВЫБРАТЬ

ВЫБОР

КОГДА &ГруппироватьПо = "Регион" ТОГДА Клиенты.Регион

КОГДА &ГруппироватьПо = "ТипКлиента" ТОГДА Клиенты.ТипКлиента

ИНАЧЕ "Общее"

КОНЕЦ КАК Группа,

СУММА(Заказы.СуммаДокумента) КАК Итого

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

ВЫБОР

КОГДА &ГруппироватьПо = "Регион" ТОГДА Клиенты.Регион

КОГДА &ГруппироватьПо = "ТипКлиента" ТОГДА Клиенты.ТипКлиента

ИНАЧЕ CONST("Общее", Строка)

КОНЕЦ

Пример 3: Условные вычисления в агрегатах

Расчёт средней суммы заказа только для определённых категорий:

ВЫБРАТЬ

Клиенты.Категория КАК КатегорияКлиента,

СРЕДНЕЕ(ВЫБОР

КОГДА Заказы.Дата > ДОБАВИТЬКДАТЕ(ТЕКУЩАЯДАТА(), МЕСЯЦ, -3) ТОГДА Заказы.СуммаДокумента

ИНАЧЕ NULL // NULL игнорируется при вычислении среднего

КОНЕЦ) КАК СредняяСуммаПоследнихЗаказов

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Категория

💡

При использовании WHEN внутри агрегатных функций помните, что NULL-значения игнорируются при вычислении СРЕДНЕЕ(), но учитываются в СУММА(). Это можно использовать для условного включения/исключения значений из расчётов.

Оптимизация запросов с множественными WHEN условиями

Запросы с большим количеством WHEN условий могут становиться "бутылочным горлышком" производительности. Вот ключевые приёмы оптимизации:

1. Вынос повторяющихся выражений

Если одно и то же выражение используется в нескольких условиях, вынесите его в отдельное поле:

ВЫБРАТЬ

Заказы.Номер КАК НомерЗаказа,

Заказы.Дата КАК ДатаЗаказа,

Заказы.СуммаДокумента КАК Сумма,

Заказы.СуммаДокумента / Заказы.КоличествоПозиций КАК СредняяЦенаПозиции,

ВЫБОР

КОГДА СредняяЦенаПозиции > 10000 ТОГДА "Премиум"

КОГДА СредняяЦенаПозиции > 5000 ТОГДА "Высокий"

КОГДА СредняяЦенаПозиции > 1000 ТОГДА "Средний"

ИНАЧЕ "Эконом"

КОНЕЦ КАК КатегорияЦены

ИЗ

Документ.ЗаказКлиента КАК Заказы

2. Использование временных таблиц

Для сложных условий с подзапросами имеет смысл разбить запрос на этапы:

// Этап 1: расчёт промежуточных данных

ВЫБРАТЬ

Клиенты.Ссылка КАК Клиент,

СУММА(Заказы.СуммаДокумента) КАК ОбщаяСумма,

МАКСИМУМ(Заказы.Дата) КАК ПоследняяДата

ПОМЕСТИТЬ ВТКлиенты

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Ссылка

ИНДЕКСИРОВАТЬ ПО

Клиент

;

////////////////////////////////////////////////

// Этап 2: применение WHEN к подготовленным данным

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

ВТКлиенты.ОбщаяСумма КАК СуммаЗаказов,

ВЫБОР

КОГДА ВТКлиенты.ОбщаяСумма > 1000000

И ВТКлиенты.ПоследняяДата > ДОБАВИТЬКДАТЕ(ТЕКУЩАЯДАТА(), МЕСЯЦ, -1) ТОГДА "Активный VIP"

КОГДА ВТКлиенты.ОбщаяСумма > 1000000 ТОГДА "VIP"

КОГДА ВТКлиенты.ПоследняяДата > ДОБАВИТЬКДАТЕ(ТЕКУЩАЯДАТА(), МЕСЯЦ, -1) ТОГДА "Активный"

ИНАЧЕ "Неактивный"

КОНЕЦ КАК СтатусКлиента

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ ВТКлиенты

ПО Клиенты.Ссылка = ВТКлиенты.Клиент

3. Оптимизация порядка условий

Располагайте условия от наиболее вероятных к наименее вероятным, и от самых "дешёвых" в вычислении к самым "дорогим":

// Неоптимально - сначала сложное условие с подзапросом

ВЫБОР

КОГДА ЕСТЬNULL(Заказы.Ссылка, ЛОЖЬ) И СУММА(Заказы.Сумма) > (ВЫБРАТЬ СРЕДНЕЕ(Сумма) ИЗ Документ.ЗаказКлиента) ТОГДА "Выше среднего"

КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.Статусы.Отменен) ТОГДА "Отменён"

ИНАЧЕ "Standard"

КОНЕЦ

// Оптимально - сначала простое условие по статусу

ВЫБОР

КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.Статусы.Отменен) ТОГДА "Отменён"

КОГДА ЕСТЬNULL(Заказы.Ссылка, ЛОЖЬ) И СУММА(Заказы.Сумма) > (ВЫБРАТЬ СРЕДНЕЕ(Сумма) ИЗ Документ.ЗаказКлиента) ТОГДА "Выше среднего"

ИНАЧЕ "Standard"

КОНЕЦ

4. Замена WHEN на объединение запросов

В некоторых случаях несколько простых запросов с UNION ALL работают быстрее, чем один сложный с множеством условий:

// Вместо:

ВЫБРАТЬ

ВЫБОР

КОГДА Тип = 1 ТОГДА ...

КОГДА Тип = 2 ТОГДА ...

КОНЕЦ

ИЗ Таблица

// Можно сделать:

ВЫБРАТЬ ... ИЗ Таблица ГДЕ Тип = 1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ ... ИЗ Таблица ГДЕ Тип = 2

💡

Для анализа производительности запросов с WHEN используйте план выполнения (включается через ПЛАН ЗАПРОСА перед основным текстом). Обратите внимание на операции TABLE SCAN — они часто указывают на неоптимальные условия.

WHEN в подзапросах и сложных конструкциях

Оператор WHEN можно успешно применять в подзапросах, что открывает дополнительные возможности для создания гибких запросов.

Пример 1: WHEN в подзапросе FROM

Создание динамической выборки на основе условий:

ВЫБРАТЬ

ОсновнойЗапрос.Клиент,

ОсновнойЗапрос.Сумма

ИЗ

(

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

ВЫБОР

КОГДА &ТолькоАктивные ТОГДА СУММА(ВЫБОР КОГДА Заказы.Статус <> ЗНАЧЕНИЕ(Перечисление.Статусы.Отменен) ТОГДА Заказы.СуммаДокумента ИНАЧЕ 0 КОНЕЦ)

ИНАЧЕ СУММА(Заказы.СуммаДокумента)

КОНЕЦ КАК Сумма

ИЗ

Справочник.Клиенты КАК Клиенты

ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК Заказы

ПО Клиенты.Ссылка = Заказы.Клиент

СГРУППИРОВАТЬ ПО

Клиенты.Наименование

) КАК ОсновнойЗапрос

ГДЕ

ОсновнойЗапрос.Сумма > 0

Пример 2: WHEN в подзапросе WHERE

Фильтрация по сложным динамическим условиям:

ВЫБРАТЬ

Номенклатура.Наименование КАК Товар,

Остатки.КоличествоОстаток КАК Остаток

ИЗ

Справочник.Номенклатура КАК Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО Номенклатура.Ссылка = Остатки.Номенклатура

ГДЕ

Номенклатура.Ссылка В (

ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура.Ссылка

ИЗ Справочник.Номенклатура КАК Номенклатура

ГДЕ

ВЫБОР

КОГДА &ТолькоАкционные ТОГДА Номенклатура.АкционныйТовар = ИСТИНА

КОГДА &ТолькоНовые ТОГДА Номенклатура.ДатаПоступления > ДОБАВИТЬКДАТЕ(ТЕКУЩАЯДАТА(), МЕСЯЦ, -1)

ИНАЧЕ ИСТИНА

КОНЕЦ

)

Пример 3: WHEN в вычисляемых полях подзапроса

Создание промежуточных вычисляемых полей с последующей фильтрацией:

ВЫБРАТЬ

Клиенты.Наименование КАК Клиент,

Результаты.Категория КАК КатегорияКлиента

ИЗ

(

ВЫБРАТЬ

Клиенты.Ссылка КАК Клиент,

ВЫБОР

КОГДА СУ