Оператор ВЫБРАТЬ КОГДА (или SELECT CASE в англоязычной терминологии) — один из самых мощных инструментов языка запросов 1С:Предприятие. Он позволяет реализовывать условную логику прямо в SQL-подобных конструкциях, избегая громоздких объединений таблиц или пост-обработки результатов на стороне клиента. Однако многие разработчики используют его неэффективно: либо перегружают запросы вложенными условиями, либо упускают возможности оптимизации.
В этой статье мы разберём синтаксис оператора на практических примерах, покажем, как комбинировать его с другими конструкциями (МЕЖДУ, В, ПОДОБНО), а также раскроем ключевые ошибки, которые приводят к падению производительности запросов в 1С. Особое внимание уделим нюансам работы с датами, перечислениями и динамическими условиями.
Если вы только начинаете осваивать язык запросов 1С, этот материал поможет избежать типичных подводных камней. Опытные разработчики найдут здесь нетривиальные кейсы применения ВЫБРАТЬ КОГДА, которые редко освещаются в стандартной документации.
1. Базовый синтаксис оператора ВЫБРАТЬ КОГДА
Конструкция ВЫБРАТЬ КОГДА работает по принципу switch-case: последовательно проверяет условия и возвращает результат первого совпадения. Если ни одно условие не выполнено, используется значение после ИНАЧЕ (аналог DEFAULT в SQL).
Общий вид:
ВЫБРАТЬ
ВЫБОР
КОГДА <Условие1> ТОГДА <Результат1>
КОГДА <Условие2> ТОГДА <Результат2>
...
ИНАЧЕ <РезультатПоУмолчанию>
КОНЕЦ КАК ПолеРезультата
ИЗ ...
Пример с классификацией клиентов по сумме заказов:
ВЫБРАТЬ
Клиенты.Наименование КАК Клиент,
ВЫБОР
КОГДА СУММА(Заказы.СуммаДокумента) > 1000000 ТОГДА "VIP"
КОГДА СУММА(Заказы.СуммаДокумента) > 100000 ТОГДА "Премиум"
ИНАЧЕ "Стандарт"
КОНЕЦ КАК КатегорияКлиента
ИЗ
Справочник.Клиенты КАК Клиенты
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Заказы КАК Заказы
ПО Клиенты.Ссылка = Заказы.Клиент
СГРУППИРОВАТЬ ПО
Клиенты.Наименование
Важно: условия проверяются последовательно, поэтому более строгие критерии должны идти первыми. Например, если поменять местами условия в примере выше, все клиенты с суммой заказов >1 млн попадут в категорию "Премиум", так как первое условие (>100000) сработает раньше.
⚠️ Внимание: В версиях 1С ниже 8.3.10 оператор ВЫБОР КОГДА не поддерживался в подзапросах. Если вам нужно использовать его в сложных конструкциях, убедитесь в актуальности платформы.
2. Примеры использования с разными типами данных
Оператор ВЫБРАТЬ КОГДА универсален и работает с любыми типами полей: числами, строками, датами, булевыми значениями и даже ссылками. Рассмотрим ключевые сценарии.
2.1. Работа с датами
Частая задача — классификация документов по периодам (например, "текущий месяц", "прошлый квартал"). Здесь удобно использовать функции НАЧАЛОПЕРИОДА() и КОНЕЦПЕРИОДА():
ВЫБРАТЬ
ВЫБОР
КОГДА Документы.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&ТекущаяДата, "Месяц")
И КОНЕЦПЕРИОДА(&ТекущаяДата, "Месяц")
ТОГДА "Текущий месяц"
КОГДА Документы.Дата >= НАЧАЛОПЕРИОДА(&ТекущаяДата, "Квартал")
ТОГДА "Текущий квартал"
ИНАЧЕ "Архив"
КОНЕЦ КАК Период
ИЗ Документ.РеализацияТоваровУслуг КАК Документы
2.2. Обработка перечислений
Если в базе есть справочник с фиксированным набором значений (например, "СтатусЗаказа"), можно заменить ссылки на читаемые строки:
ВЫБРАТЬ
ВЫБОР
КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Новый)
ТОГДА "Новый заказ"
КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Оплачен)
ТОГДА "Оплачен"
КОГДА Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Отгружен)
ТОГДА "Отгружен"
КОНЕЦ КАК СтатусТекстом
ИЗ Документ.ЗаказКлиента КАК Заказы
2.3. Динамические условия с параметрами
Параметры запроса (&Параметр) можно использовать прямо в условиях КОГДА. Например, фильтрация товаров по остаткам с учётом минимального порога:
ВЫБРАТЬ
Номенклатура.Наименование КАК Товар,
ВЫБОР
КОГДА ОстаткиТоваров.КоличествоОстаток > &МаксимальныйОстаток
ТОГДА "Избыток"
КОГДА ОстаткиТоваров.КоличествоОстаток < &МинимальныйОстаток
ТОГДА "Дефицит"
ИНАЧЕ "Норма"
КОНЕЦ КАК СостояниеОстатка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
ПО Номенклатура.Ссылка = ОстаткиТоваров.Номенклатура
- 📅 Даты: Используйте
МЕЖДУдля диапазонов иНАЧАЛОПЕРИОДА()для относительных периодов (месяц, квартал). - 📋 Перечисления: Сравнивайте со значениями через
ЗНАЧЕНИЕ(), а не строковыми представлениями. - ⚙️ Параметры: Динамические условия позволяют гибко настраивать логику без изменения кода запроса.
3. Комбинация с другими операторами: МЕЖДУ, В, ПОДОБНО
Оператор ВЫБРАТЬ КОГДА можно комбинировать с другими конструкциями языка запросов для создания сложной логики. Это особенно полезно при работе с диапазонами значений, списками или шаблонами строк.
3.1. Оператор МЕЖДУ для числовых диапазонов
Классический пример — распределение клиентов по сегментам по сумме покупок:
ВЫБРАТЬ
Клиенты.Наименование КАК Клиент,
ВЫБОР
КОГДА СУММА(Продажи.Сумма) МЕЖДУ 100000 И 500000
ТОГДА "Средний сегмент"
КОГДА СУММА(Продажи.Сумма) > 500000
ТОГДА "Крупный клиент"
ИНАЧЕ "Мелкий клиент"
КОНЕЦ КАК Сегмент
ИЗ
Справочник.Клиенты КАК Клиенты
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Продажи
ПО Клиенты.Ссылка = Продажи.Клиент
СГРУППИРОВАТЬ ПО
Клиенты.Наименование
3.2. Оператор В для проверки принадлежности списку
Если нужно проверить, входит ли значение в фиксированный набор, удобно использовать В:
ВЫБРАТЬ
Номенклатура.Наименование КАК Товар,
ВЫБОР
КОГДА Номенклатура.Группа В (&СписокПремиальныхГрупп)
ТОГДА "Премиальный товар"
КОГДА Номенклатура.Группа = ЗНАЧЕНИЕ(Справочник.ГруппыНоменклатуры.Уцененные)
ТОГДА "Уцененный товар"
КОНЕЦ КАК ТипТовара
ИЗ
Справочник.Номенклатура КАК Номенклатура
Где &СписокПремиальныхГрупп — массив ссылок на группы номенклатуры, переданный в запрос как параметр.
3.3. Оператор ПОДОБНО для строковых шаблонов
Для фильтрации по частичному совпадению строк (например, артикулов или наименований) подходит ПОДОБНО:
ВЫБРАТЬ
Номенклатура.Артикул КАК Артикул,
ВЫБОР
КОГДА Номенклатура.Артикул ПОДОБНО "АРТ-%"
ТОГДА "Старая серия"
КОГДА Номенклатура.Артикул ПОДОБНО "NEW-%"
ТОГДА "Новая серия"
КОНЕЦ КАК СерияТовара
ИЗ
Справочник.Номенклатура КАК Номенклатура
| Оператор | Пример использования | Когда применять |
|---|---|---|
МЕЖДУ |
КОГДА Сумма МЕЖДУ 1000 И 5000 |
Для числовых или временных диапазонов |
В |
КОГДА Группа В (&СписокГрупп) |
Проверка принадлежности к набору значений |
ПОДОБНО |
КОГДА Артикул ПОДОБНО "ABC-%" |
Поиск по шаблону (подстрокам, префиксам) |
И/ИЛИ |
КОГДА (Цена > 1000) И (Склад = &ОсновнойСклад) |
Сложные составные условия |
⚠️ Внимание: Оператор ПОДОБНО может значительно замедлить запрос, если применяется к неиндексированным полям. Для крупных таблиц (например, Документ.ЗаказКлиента) лучше использовать индексированные поля или предварительную фильтрацию.
ВЫБРАТЬ
ВЫБОР
КОГДА (Условие1 И Условие2) ИЛИ Условие3 ТОГДА ...
КОНЕЦ КАК Результат
ИЗ (
ВЫБРАТЬ
Условие1 КАК Условие1,
Условие2 КАК Условие2,
Условие3 КАК Условие3
ИЗ ...
) КАК Подзапрос
-->
4. Типичные ошибки и как их избежать
Несмотря на кажущуюся простоту, оператор ВЫБРАТЬ КОГДА часто становится источником проблем — от логических ошибок до падения производительности. Вот наиболее распространённые промахи:
4.1. Отсутствие условия ИНАЧЕ
Если не указать ИНАЧЕ, то для записей, не попадающих ни под одно условие, будет возвращено NULL. Это может привести к неожиданным результатам при дальнейшей обработке:
-- Плохо: нет обработки для остальных случаев
ВЫБОР
КОГДА Статус = "Оплачен" ТОГДА 1
КОГДА Статус = "Отменен" ТОГДА 0
КОНЕЦ КАК СтатусЧислом
Лучше явно указывать значение по умолчанию:
-- Хорошо: все случаи обработаны
ВЫБОР
КОГДА Статус = "Оплачен" ТОГДА 1
КОГДА Статус = "Отменен" ТОГДА 0
ИНАЧЕ -1
КОНЕЦ КАК СтатусЧислом
4.2. Избыточные условия
Если условия перекрывают друг друга, это не только усложняет поддержку кода, но и может приводить к неверным результатам. Например:
-- Плохо: второе условие избыточно
ВЫБОР
КОГДА Сумма > 100000 ТОГДА "VIP"
КОГДА Сумма > 50000 ТОГДА "Премиум" -- Никогда не сработает!
ИНАЧЕ "Стандарт"
КОНЕЦ
Упорядочивайте условия от наиболее специфичных к наименее специфичным.
4.3. Использование функций в условиях
Вычисления внутри КОГДА (например, ЛЕВ(Строка, 3)) выполняются для каждой строки, что тормозит запрос. Лучше вынести их в отдельные поля:
-- Оптимально: вычисление один раз
ВЫБРАТЬ
ЛЕВ(Номенклатура.Артикул, 3) КАК ПрефиксАртикула,
ВЫБОР
КОГДА ПрефиксАртикула = "ABC" ТОГДА "Серия A"
КОГДА ПрефиксАртикула = "XYZ" ТОГДА "Серия X"
КОНЕЦ КАК Серия
ИЗ Справочник.Номенклатура КАК Номенклатура
- 🔍 Пропущенное ИНАЧЕ: Всегда обрабатывайте все возможные случаи, даже если "их не должно быть".
- 📉 Избыточные условия: Проверяйте, не перекрываются ли ваши
КОГДАдруг с другом. - 🐢 Функции в условиях: Выносите вычисления за пределы
ВЫБОР, чтобы избежать повторных расчётов. - 🗑️ Нечитаемые вложенности: Если внутри
КОГДАбольше 3-х уровней вложенных условий, разбейте запрос на части.
Почему запрос с ВЫБРАТЬ КОГДА может работать медленно?
Если в условиях используются неиндексированные поля (например, строковые функции или вычисления), СУБД не может оптимизировать выполнение через индексы. В результате запрос сканирует всю таблицу (table scan), а не использует быстрый поиск по индексу (index seek). Особенно критично это для крупных таблиц (например, Документ.ПоступлениеТоваров с миллионами записей).
5. Оптимизация запросов с ВЫБРАТЬ КОГДА
Запросы с большим количеством условий КОГДА могут становиться "бутылочным горлышком" производительности. Вот ключевые приёмы оптимизации:
5.1. Использование индексированных полей
Убедитесь, что поля, используемые в условиях КОГДА, имеют индексы в базе данных. Например, если вы фильтруете по полю Дата, оно должно быть проиндексировано. Проверить индексы можно через консоль администратора 1С или SQL-профайлер.
5.2. Замена на соединения (JOIN)
Если условия КОГДА проверяют принадлежность к справочникам, иногда эффективнее использовать соединения:
-- Вместо:
ВЫБРАТЬ
ВЫБОР
КОГДА Товары.Категория = &Категория1 ТОГДА "Категория 1"
КОГДА Товары.Категория = &Категория2 ТОГДА "Категория 2"
КОНЕЦ КАК КатегорияТекстом
ИЗ Справочник.Номенклатура КАК Товары
-- Лучше:
ВЫБРАТЬ
Товары.Наименование,
Категории.Наименование КАК КатегорияТекстом
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КатегорииТоваров КАК Категории
ПО Товары.Категория = Категории.Ссылка
ГДЕ Категории.Ссылка В (&СписокКатегорий)
5.3. Разделение сложных запросов
Если запрос содержит более 5-7 условий КОГДА, рассмотрите возможность разбить его на несколько простых с использованием временных таблиц:
ВЫБРАТЬ
Товары.Ссылка КАК Ссылка,
ВЫБОР
КОГДА Остатки.Количество > 100 ТОГДА "Много"
ИНАЧЕ "Мало"
КОНЕЦ КАК Наличие
ПОМЕСТИТЬ ВТОстатки
ИЗ ...
;
ВЫБРАТЬ
Товары.Наименование,
Остатки.Наличие,
ВЫБОР
КОГДА Товары.Цена > 10000 ТОГДА "Дорогой"
ИНАЧЕ "Дешевый"
КОНЕЦ КАК ЦеноваяКатегория
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ ВТОстатки КАК Остатки
ПО Товары.Ссылка = Остатки.Ссылка
5.4. Кеширование повторяющихся вычислений
Если одно и то же выражение используется в нескольких условиях, вынесите его в отдельное поле:
ВЫБРАТЬ
СУММА(Продажи.Сумма) КАК ОбщаяСумма,
ВЫБОР
КОГДА ОбщаяСумма > 1000000 ТОГДА "VIP"
КОГДА ОбщаяСумма > 100000 ТОГДА "Премиум"
КОНЕЦ КАК Категория
ИЗ ...
Поля в условиях имеют индексы|Сложные вычисления вынесены в отдельные поля|Количество условий КОГДА не превышает 5-7|Использованы соединения вместо вложенных ВЫБОРов|Проверено выполнение через EXPLAIN (в SQL-профайлере)
-->
Самая частая причина медленных запросов с ВЫБРАТЬ КОГДА — отсутствие индексов на полях, используемых в условиях. Всегда проверяйте план выполнения запроса в SQL-профайлере!
6. Практический пример: сложный отчёт с классификацией данных
Рассмотрим реальный кейс: нужно построить отчёт по продажам с классификацией товаров по нескольким критериям:
- По сумме продаж (топ/середняк/аутсайдер).
- По динамике продаж (растущий/падающий/стабильный).
- По категории товара (премиум/стандарт/эконом).
Исходный запрос с вложенными ВЫБОР:
ВЫБРАТЬ
Товары.Наименование КАК Товар,
СУММА(Продажи.Количество) КАК ПроданоШтук,
СУММА(Продажи.Сумма) КАК Выручка,
-- Классификация по сумме продаж
ВЫБОР
КОГДА СУММА(Продажи.Сумма) > 500000 ТОГДА "Топ"
КОГДА СУММА(Продажи.Сумма) > 50000 ТОГДА "Средний"
ИНАЧЕ "Аутсайдер"
КОНЕЦ КАК СегментПоВыручке,
-- Классификация по динамике (сравнение с прошлым месяцем)
ВЫБОР
КОГДА СУММА(Продажи.Количество) > ЛАГ(СУММА(Продажи.Количество), 1) ОКНО (ПАРТИЦИЯ ПО Товары.Ссылка УПОРЯДОЧИТЬ ПО Продажи.Дата)
ТОГДА "Растущий"
КОГДА СУММА(Продажи.Количество) < ЛАГ(СУММА(Продажи.Количество), 1) ОКНО (ПАРТИЦИЯ ПО Товары.Ссылка УПОРЯДОЧИТЬ ПО Продажи.Дата)
ТОГДА "Падающий"
ИНАЧЕ "Стабильный"
КОНЕЦ КАК ДинамикаПродаж,
-- Классификация по категории товара
ВЫБОР
КОГДА Товары.Категория = ЗНАЧЕНИЕ(Справочник.КатегорииТоваров.Премиум)
ТОГДА "Премиум"
КОГДА Товары.Категория = ЗНАЧЕНИЕ(Справочник.КатегорииТоваров.Эконом)
ТОГДА "Эконом"
ИНАЧЕ "Стандарт"
КОНЕЦ КАК КатегорияТовара
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Продажи
ПО Товары.Ссылка = Продажи.Товар
ГДЕ
Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
Товары.Наименование,
Товары.Категория
Оптимизированная версия (с предварительным расчётом динамики):
-- Шаг 1: расчёт продаж по месяцам
ВЫБРАТЬ
Товары.Ссылка КАК Товар,
НАЧАЛОПЕРИОДА(Продажи.Дата, "Месяц") КАК Месяц,
СУММА(Продажи.Количество) КАК ПроданоШтук
ПОМЕСТИТЬ ВТПродажиПоМесяцам
ИЗ ...
ГДЕ Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО Товары.Ссылка, НАЧАЛОПЕРИОДА(Продажи.Дата, "Месяц")
;
-- Шаг 2: расчёт динамики
ВЫБРАТЬ
Товар,
Месяц,
ПроданоШтук,
ЛАГ(ПроданоШтук, 1) ОКНО (ПАРТИЦИЯ ПО Товар УПОРЯДОЧИТЬ ПО Месяц) КАК ПроданоПредыдущийМесяц
ПОМЕСТИТЬ ВТДинамика
ИЗ ВТПродажиПоМесяцам
;
-- Шаг 3: финальный отчёт
ВЫБРАТЬ
Товары.Наименование КАК Товар,
СУММА(Продажи.Сумма) КАК Выручка,
ВЫБОР
КОГДА СУММА(Продажи.Сумма) > 500000 ТОГДА "Топ"
ИНАЧЕ "Прочие"
КОНЕЦ КАК СегментПоВыручке,
МАКСИМУМ(
ВЫБОР
КОГДА Динамика.ПроданоШтук > Динамика.ПроданоПредыдущийМесяц ТОГДА "Растущий"
КОГДА Динамика.ПроданоШтук < Динамика.ПроданоПредыдущийМесяц ТОГДА "Падающий"
ИНАЧЕ "Стабильный"
КОНЕЦ
) КАК ДинамикаПродаж
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Продажи
ПО Товары.Ссылка = Продажи.Товар
ЛЕВОЕ СОЕДИНЕНИЕ ВТДинамика КАК Динамика
ПО Товары.Ссылка = Динамика.Товар
ГДЕ Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО Товары.Наименование
Такой подход уменьшает нагрузку на СУБД за счёт:
- Разделения сложной логики на простые шаги.