Конструкция «иначе когда»** в языке запросов 1С:Предприятие 8.3 — один из самых спорных и часто неправильно используемых элементов. Многие разработчики путают её с оператором ЕСЛИ в встроенном языке или конструкцией ВЫБОР, что приводит к логическим ошибкам, замедлению выполнения запросов или даже синтаксическим сбоям. В этой статье разберём, почему «иначе когда» работает иначе, чем кажется на первый взгляд, как её правильно применять в разных сценариях и какие подводные камни скрываются за простым, на первый взгляд, синтаксисом.
Особенность конструкции в том, что она не является полноценной заменой условным операторам — её задача другая: группировка данных в результате запроса на основе нескольких условий. При этом порядок проверки условий, приоритеты и даже возможность использования в разных секциях запроса (например, в ГДЕ vs ВЫБРАТЬ) имеют критичное значение. Если вы когда-нибудь сталкивались с ошибкой «Недопустимое использование ключевого слова ИНАЧЕКОГДА», эта статья поможет разобраться в её причинах.
Чем «иначе когда» отличается от «если» и «выбор»
Основная путаница возникает из-за внешнего сходства конструкций. Давайте чётко разграничим их:
- 🔹
ЕСЛИ... ТО... ИНАЧЕ— оператор встроенного языка 1С, работает в модулях, процедурах и функциях. Поддерживает вложенные условия, но не может использоваться напрямую в тексте запроса. - 🔹
ВЫБОР... КОГДА... ИНАЧЕ— конструкция встроенного языка, аналогичнаswitch-caseв других языках программирования. Также недоступна в запросах. - 🔹
ИНАЧЕ КОГДА— элемент языка запросов, используется только в секцияхВЫБРАТЬ,ГДЕилиУПОРЯДОЧИТЬ ПО. Работает как часть выражения, а не какный оператор.
Ключевое отличие: ИНАЧЕКОГДА не управляет потоком выполнения кода (как ЕСЛИ), а формирует вычисляемое поле в результате запроса. Например, в запросе:
ВЫБРАТЬ
ВЫБОР
КОГДА СуммаДокумента > 100000 ТОГДА"Крупный"
ИНАЧЕ КОГДА СуммаДокумента > 50000 ТОГДА"Средний"
ИНАЧЕ"Мелкий"
КОНЕЦ КАК КатегорияСделки
ИЗ Документ.РеализацияТоваровУслуг
конструкция создаёт новое поле КатегорияСделки, значение которого зависит от условия. В то время как ЕСЛИ в модуле мог бы, например, прервать выполнение процедуры или вызвать исключение.
Синтаксис конструкции: правила и ограничения
Формальный синтаксис конструкции выглядит так:
ВЫБОР
КОГДА <Условие1> ТОГДА <Выражение1>
ИНАЧЕ КОГДА <Условие2> ТОГДА <Выражение2>
[ИНАЧЕ <ВыражениеПоУмолчанию>]
КОНЕЦ
Но на практике есть нюансы, которые часто упускают:
- Обязательное наличие
ВЫБОР... КОНЕЦ. КонструкцияИНАЧЕКОГДАне может использоваться отдельно — только внутри блокаВЫБОР. - Порядок проверки условий. Условия оцениваются сверху вниз, и при первом совпадении дальнейшие проверки не выполняются. Это важно для взаимозависимых условий (например, проверки диапазонов).
- Ограничение на типы данных. Все выражения в блоках
ТОГДАдолжны возвращать совместимые типы (например, нельзя смешивать строки и числа без явного приведения).
Типичная ошибка — попытка использовать ИНАЧЕКОГДА в секции ГДЕ без обёртки в ВЫБОР:
// НЕПРАВИЛЬНО!
ВЫБРАТЬ *
ИЗ Документ.ЗаказыПокупателей
ГДЕ ИНАЧЕ КОГДА Статус ="Оплачен" ТОГДА ДатаОплаты > &ТекущаяДата
Такой запрос вызовет ошибку. Правильный вариант:
ВЫБРАТЬ *
ИЗ Документ.ЗаказыПокупателей
ГДЕ ВЫБОР
КОГДА Статус ="Оплачен" ТОГДА ДатаОплаты > &ТекущаяДата
ИНАЧЕ 1 = 1 // Всегда истина для остальных случаев
КОНЕЦ
Если вам нужно отфильтровать данные по нескольким альтернативным условиям, вместо ИНАЧЕКОГДА в ГДЕ проще использовать оператор ИЛИ. Конструкция ВЫБОР здесь избыточна и может снизить производительность.
Примеры использования в реальных задачах
Рассмотрим практические сценарии, где ИНАЧЕКОГДА действительно полезен.
1. Категоризация данных в отчётах
Допустим, нужно разделить клиентов на группы по сумме покупок за год:
ВЫБРАТЬ
Клиент,
СУММА(СуммаДокумента) КАК ОбщаяСумма,
ВЫБОР
КОГДА СУММА(СуммаДокумента) > 1000000 ТОГДА"VIP"
ИНАЧЕ КОГДА СУММА(СуммаДокумента) > 500000 ТОГДА"Премиум"
ИНАЧЕ КОГДА СУММА(СуммаДокумента) > 100000 ТОГДА"Стандарт"
ИНАЧЕ"Базовый"
КОНЕЦ КАК КатегорияКлиента
ИЗ Документ.РеализацияТоваровУслуг КАК Реализация
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Клиенты
ПО Реализация.Контрагент = Клиенты.Ссылка
СГРУППИРОВАТЬ ПО Клиент
2. Динамическое формирование полей
Если нужно вывести разные поля в зависимости от типа документа:
ВЫБРАТЬ
ВЫБОР
КОГДА ВидДокумента ="ЗаказПокупателя" ТОГДА ДатаПоступления
ИНАЧЕ КОГДА ВидДокумента ="Реализация" ТОГДА ДатаОтгрузки
ИНАЧЕ NULL
КОНЕЦ КАК КлючеваяДата
ИЗ Документ.ЗаказыПокупателей ИСТИНА
3. Условная сортировка
В секции УПОРЯДОЧИТЬ ПО можно использовать ИНАЧЕКОГДА для гибкой сортировки:
ВЫБРАТЬ *
ИЗ Документ.ЗаказыПокупателей
УПОРЯДОЧИТЬ ПО
ВЫБОР
КОГДА Статус ="Срочный" ТОГДА 1
ИНАЧЕ КОГДА Статус ="Оплачен" ТОГДА 2
ИНАЧЕ 3
КОНЕЦ,
ДатаДокумента УБЫВ
Почему нельзя использовать агрегатные функции в условиях ИНАЧЕКОГДА?
Внутри конструкции ВЫБОР... ИНАЧЕКОГДА нельзя напрямую использовать агрегатные функции (например, СУММА или МАКСИМУМ) в условиях КОГДА. Это связано с тем, что условия оцениваются для каждой строки отдельно, а агрегатные функции требуют предварительной группировки данных. Чтобы обойти ограничение, используйте подзапросы или вычисляйте агрегаты заранее в отдельных полях.
Типичные ошибки и как их избежать
Даже опытные разработчики иногда допускают ошибки при работе с ИНАЧЕКОГДА. Вот самые распространённые:
| Ошибка | Причина | Как исправить |
|---|---|---|
| «Недопустимое использование ключевого слова ИНАЧЕКОГДА» | Отсутствует обёртка в ВЫБОР... КОНЕЦ или конструкция используется в недопустимой секции запроса (например, в ИМЕЮЩИЕ) |
Проверьте синтаксис: ИНАЧЕКОГДА должно быть внутри ВЫБОР и использоваться только в ВЫБРАТЬ, ГДЕ или УПОРЯДОЧИТЬ ПО |
| «Типы не совместимы» | Выражения в блоках ТОГДА возвращают разные типы (например, строка и число) |
Приведите все выражения к одному типу с помощью ПРЕОБРАЗОВАТЬ или ЗНАЧЕНИЕ |
| Некорректная логика условий | Условия перекрывают друг друга или расположены в неправильном порядке (например, проверка диапазона >100 идёт после >50) |
Сортируйте условия от наиболее специфичных к наименее специфичным |
Ещё одна частая проблема — избыточные проверки. Например:
ВЫБОР
КОГДА Статус ="Оплачен" ТОГДА"Оплачен"
ИНАЧЕ КОГДА Статус ="Отменён" ТОГДА"Отменён"
ИНАЧЕ КОГДА Статус ="В работе" ТОГДА"В работе"
ИНАЧЕ"Неопределён"
КОНЕЦ
Здесь конструкция избыточна — достаточно простой проверки:
ВЫБОР
КОГДА Статус В ("Оплачен","Отменён","В работе") ТОГДА Статус
ИНАЧЕ"Неопределён"
КОНЕЦ
Убедитесь, что конструкция обёрнута в ВЫБОР... КОНЕЦ|
Проверьте совместимость типов возвращаемых значений|
Отсортируйте условия от наиболее специфичных к общим|
Удалите избыточные проверки (например, КОГДА А = 1 ТОГДА"А")|
Протестируйте запрос на небольшом наборе данных-->
Производительность: что быстрее — «иначе когда» или постобработка?
Один из самых спорных вопросов: где лучше обрабатывать условную логику — в самом запросе (с помощью ИНАЧЕКОГДА) или после получения данных (в модуле на встроенном языке)? Ответ зависит от контекста:
- 📊 В запросе:
- ✅ Плюсы: данные категоризируются на уровне СУБД, что уменьшает объём передаваемых данных.
- ❌ Минусы: сложная логика может замедлить выполнение запроса, особенно если условия затрагивают несгруппированные данные.
- 💻 В модуле:
- ✅ Плюсы: гибкость — можно использовать любые операторы встроенного языка (
ЕСЛИ, циклы, обращения к другим объектам). - ❌ Минусы: увеличивается нагрузка на сервер 1С, так как данные передаются «как есть», а обработка происходит позже.
- ✅ Плюсы: гибкость — можно использовать любые операторы встроенного языка (
Общее правило:
⚠️ Внимание: Если условная логика простая (например, разделение на 2-3 категории по одному полю), используйте ИНАЧЕКОГДА в запросе. Если условия сложные (вложенные проверки, обращения к другим таблицам, вызов методов), перенесите логику в модуль.
Пример, когда постобработка предпочтительнее:
// В запросе:
ВЫБРАТЬ
Ссылка,
СуммаДокумента,
Контрагент
ИЗ Документ.РеализацияТоваровУслуг
// В модуле:
Для Каждого Строка Из РезультатЗапроса Цикл
Если Строка.СуммаДокумента > 100000 И Строка.Контрагент.ЭтоГруппа Тогда
Строка.Категория ="Корпоративный";
ИначеЕсли Строка.Контрагент.Поставщик Тогда
Строка.Категория ="Поставщик";
КонецЕсли;
КонецЦикла;
Здесь логика включает проверку ЭтоГруппа и Поставщик, что невозможно сделать в чистом SQL-запросе.
Конструкция ИНАЧЕКОГДА оптимальна для простых категоризаций по полям текущей таблицы. Для сложной логики с обращениями к другим объектам или методам лучше использовать постобработку на встроенном языке.
Альтернативы: когда «иначе когда» не подходит
В некоторых случаях ИНАЧЕКОГДА либо невозможно использовать, либо это неоптимально. Рассмотрим альтернативы:
1. Оператор ВЫРАЗИТЬ (CASE в SQL)
В новых версиях платформы (8.3.14+) можно использовать более гибкий оператор ВЫРАЗИТЬ, который ближе к стандартному SQL CASE:
ВЫБРАТЬ
ВЫРАЗИТЬ(
КОГДА Сумма > 1000 ТОГДА"Большая"
КОГДА Сумма > 100 ТОГДА"Средняя"
ИНАЧЕ"Малая"
) КАК РазмерСделки
ИЗ Документ.ЗаказыПокупателей
Преимущество: более лаконичный синтаксис и лучшая читаемость.
2. Объединение запросов (ОБЪЕДИНИТЬ)
Если нужно выбрать данные из разных источников на основе условия, иногда эффективнее использовать ОБЪЕДИНИТЬ:
ВЫБРАТЬ
"Оплаченные" КАК Тип,
Сумма
ИЗ Документ.ЗаказыПокупателей
ГДЕ Статус ="Оплачен"
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Неоплаченные" КАК Тип,
Сумма
ИЗ Документ.ЗаказыПокупателей
ГДЕ Статус <>"Оплачен"
3. Временные таблицы
Для сложных условий с агрегацией можно использовать временные таблицы:
// Сначала собираем агрегированные данные
ВЫБРАТЬ
Контрагент,
СУММА(СуммаДокумента) КАК ОбщаяСумма
ИЗ Документ.РеализацияТоваровУслуг
СГРУППИРОВАТЬ ПО Контрагент
ПОМЕСТИТЬ ВТ_Агрегаты
// Затем категоризируем
ВЫБРАТЬ
ВТ_Агрегаты.Контрагент,
ВТ_Агрегаты.ОбщаяСумма,
ВЫБОР
КОГДА ВТ_Агрегаты.ОбщаяСумма > 100000 ТОГДА"VIP"
ИНАЧЕ"Standard"
КОНЕЦ КАК Категория
ИЗ ВТ_Агрегаты КАК ВТ_Агрегаты
Если вам нужно применить одно и то же условие категоризации в нескольких запросах, вынесите логику в функцию на встроенном языке и вызывайте её через ВЫРАЗИТЬ. Это упростит поддержку кода.
Отладка и тестирование запросов с «иначе когда»
Ошибки в конструкции ИНАЧЕКОГДА часто проявляются неочевидным образом: запрос выполняется, но возвращает неверные данные. Вот как их диагностировать:
- Проверка порядка условий: Убедитесь, что условия расположены от наиболее строгих к наиболее общим. Например, проверка
Сумма > 1000должна идти послеСумма > 10000, а не до. - Тестирование на граничных значениях: Прогоняйте запрос с данными, которые попадают на границы условий (например, сумма ровно 1000 или 10000).
- Использование
ПОКАЗАТЬ ПЛАН ЗАПРОСА: Если запрос работает медленно, проверьте план выполнения. Сложные условия вИНАЧЕКОГДАмогут привести к полному сканированию таблиц.
Пример отладочного запроса для проверки логики:
ВЫБРАТЬ
СуммаДокумента,
ВЫБОР
КОГДА СуммаДокумента > 10000 ТОГДА"Большая"
ИНАЧЕ КОГДА СуммаДокумента > 1000 ТОГДА"Средняя"
ИНАЧЕ"Малая"
КОНЕЦ КАК Категория,
// Дополнительные поля для отладки
ВЫБОР
КОГДА СуммаДокумента > 10000 ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК Диагностика_Условие1,
ВЫБОР
КОГДА СуммаДокумента > 1000 ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК Диагностика_Условие2
ИЗ Документ.РеализацияТоваровУслуг
ГДЕ СуммаДокумента МЕЖДУ 900 И 11000 // Граничные значения
УПОРЯДОЧИТЬ ПО СуммаДокумента УБЫВ
Такой запрос поможет увидеть, как именно срабатывают условия для пограничных значений.
⚠️ Внимание: Если вы используете ИНАЧЕКОГДА в запросах к внешним источникам данных (например, через OLE DB или HTTP-сервисы), учитывайте, что некоторые СУБД могут не поддерживать полный синтаксис конструкции. В таких случаях переносите логику на сторону 1С.
FAQ: Частые вопросы по «иначе когда» в 1С 8.3
Можно ли использовать ИНАЧЕКОГДА в подзапросах?
Да, но с оговорками. Конструкция работает в подзапросах, если они возвращают скалярное значение (одно поле). Например:
ВЫБРАТЬ
(ВЫБРАТЬ
ВЫБОР
КОГДА СУММА(Сумма) > 1000 ТОГДА 1
ИНАЧЕ 0
КОНЕЦ
ИЗ Документ.ЗаказыПокупателей
ГДЕ Контрагент = ВНЕШНЯЯТАБЛИЦА.Контрагент) КАК ЕстьКрупныеСделки
ИЗ Справочник.Контрагенты КАК ВНЕШНЯЯТАБЛИЦА
Однако нельзя использовать ИНАЧЕКОГДА в подзапросах, которые возвращают несколько полей или используются в секции ГДЕ без обёртки в ВЫБОР.
Почему запрос с ИНАЧЕКОГДА работает медленно?
Чаще всего это связано с:
- 🔍 Отсутствием индексов по полям, используемым в условиях.
- 🔄 Сложными вложенными условиями, которые не оптимизируются СУБД.
- 📊 Применением конструкции к несгруппированным данным (например, агрегатные функции внутри
ИНАЧЕКОГДАбез предварительной группировки).
Решения:
- 🛠️ Проверьте наличие индексов по полям в условиях.
- 🔄 Разбейте сложный запрос на несколько простых с использованием временных таблиц.
- 📊 Перенесите логику категоризации в модуль, если она слишком сложная.
Можно ли в ИНАЧЕКОГДА использовать функции встроенного языка?
Нет, напрямую — нельзя. Конструкция работает на уровне языка запросов, который не имеет доступа к методам встроенного языка (например, НАЧИНАЕТСЯС, ТИПЗНАЧЕНИЯ).
Альтернативы:
- 🔧 Используйте SQL-функции (например,
ЛЕВ,ПРАВдля работы со строками). - 🔄 Перенесите логику в модуль и используйте
ВЫПОЛНИТЬЗАПРОСс постобработкой. - 📝 Для сложных проверок создайте вычисляемые поля в виртуальных таблицах.
Как обработать NULL в условиях ИНАЧЕКОГДА?
NULL в условиях ведёт себя неинтуитивно. Например, конструкция:
ВЫБОР
КОГДА Поле = 100 ТОГДА"Сто"
ИНАЧЕ"Другое"
КОНЕЦ
вернёт "Другое" не только для значений ≠ 100, но и для NULL. Чтобы явно обработать NULL, добавьте отдельное условие:
ВЫБОР
КОГДА Поле ЕСТЬ NULL ТОГДА"Не заполнено"
КОГДА Поле = 100 ТОГДА"Сто"
ИНАЧЕ"Другое"
КОНЕЦ
Используйте ЕСТЬ NULL или ЗНАЧЕНИЕЗАПОЛНЕНО (в новых версиях платформы) для явной проверки.
Можно ли вложить один ВЫБОР... ИНАЧЕКОГДА в другой?
Технически — да, но это крайне не рекомендуется. Вложенные конструкции:
- ❌ Значительно усложняют чтение и поддержку кода.
- ❌ Могут привести к ошибкам из-за несовместимости типов на разных уровнях вложенности.
- ❌ Часто становятся причиной низкой производительности.
Альтернатива: разбейте логику на несколько простых ВЫБОР или перенесите часть условий в постобработку.