Конструкция «иначе когда»** в языке запросов 1С:Предприятие 8.3 — один из самых спорных и часто неправильно используемых элементов. Многие разработчики путают её с оператором ЕСЛИ в встроенном языке или конструкцией ВЫБОР, что приводит к логическим ошибкам, замедлению выполнения запросов или даже синтаксическим сбоям. В этой статье разберём, почему «иначе когда» работает иначе, чем кажется на первый взгляд, как её правильно применять в разных сценариях и какие подводные камни скрываются за простым, на первый взгляд, синтаксисом.

Особенность конструкции в том, что она не является полноценной заменой условным операторам — её задача другая: группировка данных в результате запроса на основе нескольких условий. При этом порядок проверки условий, приоритеты и даже возможность использования в разных секциях запроса (например, в ГДЕ vs ВЫБРАТЬ) имеют критичное значение. Если вы когда-нибудь сталкивались с ошибкой «Недопустимое использование ключевого слова ИНАЧЕКОГДА», эта статья поможет разобраться в её причинах.

Чем «иначе когда» отличается от «если» и «выбор»

Основная путаница возникает из-за внешнего сходства конструкций. Давайте чётко разграничим их:

  • 🔹 ЕСЛИ... ТО... ИНАЧЕ — оператор встроенного языка 1С, работает в модулях, процедурах и функциях. Поддерживает вложенные условия, но не может использоваться напрямую в тексте запроса.
  • 🔹 ВЫБОР... КОГДА... ИНАЧЕ — конструкция встроенного языка, аналогична switch-case в других языках программирования. Также недоступна в запросах.
  • 🔹 ИНАЧЕ КОГДАэлемент языка запросов, используется только в секциях ВЫБРАТЬ, ГДЕ или УПОРЯДОЧИТЬ ПО. Работает как часть выражения, а не какный оператор.

Ключевое отличие: ИНАЧЕКОГДА не управляет потоком выполнения кода (как ЕСЛИ), а формирует вычисляемое поле в результате запроса. Например, в запросе:

ВЫБРАТЬ

ВЫБОР

КОГДА СуммаДокумента > 100000 ТОГДА"Крупный"

ИНАЧЕ КОГДА СуммаДокумента > 50000 ТОГДА"Средний"

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

КОНЕЦ КАК КатегорияСделки

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

конструкция создаёт новое поле КатегорияСделки, значение которого зависит от условия. В то время как ЕСЛИ в модуле мог бы, например, прервать выполнение процедуры или вызвать исключение.

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

Синтаксис конструкции: правила и ограничения

Формальный синтаксис конструкции выглядит так:

ВЫБОР

КОГДА <Условие1> ТОГДА <Выражение1>

ИНАЧЕ КОГДА <Условие2> ТОГДА <Выражение2>

[ИНАЧЕ <ВыражениеПоУмолчанию>]

КОНЕЦ

Но на практике есть нюансы, которые часто упускают:

  1. Обязательное наличие ВЫБОР... КОНЕЦ. Конструкция ИНАЧЕКОГДА не может использоваться отдельно — только внутри блока ВЫБОР.
  2. Порядок проверки условий. Условия оцениваются сверху вниз, и при первом совпадении дальнейшие проверки не выполняются. Это важно для взаимозависимых условий (например, проверки диапазонов).
  3. Ограничение на типы данных. Все выражения в блоках ТОГДА должны возвращать совместимые типы (например, нельзя смешивать строки и числа без явного приведения).

Типичная ошибка — попытка использовать ИНАЧЕКОГДА в секции ГДЕ без обёртки в ВЫБОР:

// НЕПРАВИЛЬНО!

ВЫБРАТЬ *

ИЗ Документ.ЗаказыПокупателей

ГДЕ ИНАЧЕ КОГДА Статус ="Оплачен" ТОГДА ДатаОплаты > &ТекущаяДата

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

ВЫБРАТЬ *

ИЗ Документ.ЗаказыПокупателей

ГДЕ ВЫБОР

КОГДА Статус ="Оплачен" ТОГДА ДатаОплаты > &ТекущаяДата

ИНАЧЕ 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"

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

ИЗ ВТ_Агрегаты КАК ВТ_Агрегаты

💡

Если вам нужно применить одно и то же условие категоризации в нескольких запросах, вынесите логику в функцию на встроенном языке и вызывайте её через ВЫРАЗИТЬ. Это упростит поддержку кода.

Отладка и тестирование запросов с «иначе когда»

Ошибки в конструкции ИНАЧЕКОГДА часто проявляются неочевидным образом: запрос выполняется, но возвращает неверные данные. Вот как их диагностировать:

  1. Проверка порядка условий: Убедитесь, что условия расположены от наиболее строгих к наиболее общим. Например, проверка Сумма > 1000 должна идти после Сумма > 10000, а не до.
  2. Тестирование на граничных значениях: Прогоняйте запрос с данными, которые попадают на границы условий (например, сумма ровно 1000 или 10000).
  3. Использование ПОКАЗАТЬ ПЛАН ЗАПРОСА: Если запрос работает медленно, проверьте план выполнения. Сложные условия в ИНАЧЕКОГДА могут привести к полному сканированию таблиц.

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

ВЫБРАТЬ

СуммаДокумента,

ВЫБОР

КОГДА СуммаДокумента > 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 или ЗНАЧЕНИЕЗАПОЛНЕНО (в новых версиях платформы) для явной проверки.

Можно ли вложить один ВЫБОР... ИНАЧЕКОГДА в другой?

Технически — да, но это крайне не рекомендуется. Вложенные конструкции:

  • ❌ Значительно усложняют чтение и поддержку кода.
  • ❌ Могут привести к ошибкам из-за несовместимости типов на разных уровнях вложенности.
  • ❌ Часто становятся причиной низкой производительности.

Альтернатива: разбейте логику на несколько простых ВЫБОР или перенесите часть условий в постобработку.