В языке запросов 1С:Предприятие конструкция КОГДА (аналог CASE WHEN в SQL) позволяет реализовывать сложную логику прямо в тексте запроса без обращения к встроенному языку. Это мощный инструмент для трансформации данных на лету, категоризации записей или замены значений по условию. Однако его синтаксис имеет нюансы, которые часто становятся источником ошибок — от неверной расстановки ключевых слов до логических противоречий в условиях.
В этой статье разберём все варианты использования КОГДА: от простых замен значений до вложенных конструкций с агрегатными функциями. Особое внимание уделим типичным ошибкам (например, проблеме неявного приведения типов при сравнении дат и чисел в одном выражении), а также оптимизации запросов с большим количеством условий. Материал будет полезен как начинающим разработчикам, так и опытным специалистам, которые хотят глубже понять механизмы работы языка запросов 1С 8.3.
1. Синтаксис конструкции КОГДА: базовые правила
Конструкция КОГДА в запросах 1С имеет два основных формата:
- 🔹 Простое условие:
КОГДА Условие ТОГДА Значение1 ИНАЧЕ Значение2— аналог тернарного оператора. - 🔹 Множественное ветвление:
КОГДА Условие1 ТОГДА Значение1 ... КОГДА УсловиеN ТОГДА ЗначениеN ИНАЧЕ ЗначениеПоУмолчанию— аналогCASE WHEN ... THEN ... ELSE.
Ключевые особенности синтаксиса:
- 📌 Ключевое слово
ТОГДАобязательно после каждого условия. - 📌 Блок
ИНАЧЕне обязателен — если его нет, а ни одно условие не выполнилось, результат будетNULL. - 📌 Условия оцениваются последовательно, и выполнение прекращается при первом совпадении (как в
switch-caseв других языках).
Пример простого использования:
ВЫБРАТЬ
КОГДА СуммаДокумента > 100000 ТОГДА "Крупный"
ИНАЧЕ "Мелкий" КАК КатегорияСделки,
СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг
⚠️ Внимание: В отличие от встроенного языка, где можно использовать ? для тернарного оператора, в запросах 1С такой синтаксис недопустим. Конструкция КОГДА — единственный способ реализовать условную логику.
2. Сравнение с CASE в SQL: ключевые различия
Разработчики, пришедшие из SQL, часто пытаются использовать CASE WHEN в запросах 1С, что приводит к ошибкам. Основные отличия:
| Функциональность | SQL (CASE WHEN) | 1С (КОГДА) |
|---|---|---|
| Синтаксис начала | CASE WHEN Условие THEN | КОГДА Условие ТОГДА |
| Завершение условия | END | Не требуется |
| Вложенные условия | Поддерживаются | Поддерживаются, но с ограничениями на глубину |
| NULL в ИНАЧЕ | Явное указание NULL | Автоматически, если блок ИНАЧЕ отсутствует |
Пример эквивалентного запроса в SQL и 1С:
-- SQL
SELECT
CASE WHEN Price > 1000 THEN 'Expensive'
WHEN Price > 500 THEN 'Medium'
ELSE 'Cheap' END AS PriceCategory
FROM Products
-- 1С
ВЫБРАТЬ
КОГДА Цена > 1000 ТОГДА "Дорогой"
КОГДА Цена > 500 ТОГДА "Средний"
ИНАЧЕ "Дешёвый" КАК КатегорияЦены
ИЗ
Справочник.Номенклатура
Важное замечание: в 1С нельзя использовать CASE как выражение в ORDER BY или GROUP BY без предварительного присвоения псевдонима в SELECT. В SQL такое ограничение отсутствует.
3. Работа с типами данных: даты, числа, строки
Одна из самых распространённых ошибок при использовании КОГДА — неявное приведение типов. Например, сравнение даты с числом или строки с датой может привести к неожиданным результатам.
Правила приведения типов в условиях:
- 📅 Даты: Сравниваются как даты, но при операции с числами преобразуются в количество дней с 01.01.0001.
- 🔢 Числа: Автоматически приводятся к числовому типу, но строки вроде
"100"не преобразуются в число. - 📜 Строки: Сравнение регистрозависимое (в отличие от оператора
ПОДОБНО).
Примеры корректного сравнения:
-- Сравнение дат
ВЫБРАТЬ
КОГДА ДатаДокумента >= ДАТАВРЕМЯ(2023, 1, 1) ТОГДА "Актуальный"
ИНАЧЕ "Устаревший" КАК Статус
-- Сравнение чисел со строками (требуется явное приведение)
ВЫБРАТЬ
КОГДА ЧИСЛО(Код) > 1000 ТОГДА "Большой код"
ИНАЧЕ "Маленький код" КАК КатегорияКода
⚠️ Внимание: При сравнении полей типаБулевоиспользуйте явные значенияИСТИНА/ЛОЖЬ, а не1/0. В противном случае условиеКОГДА ПометкаУдаления = 1не сработает корректно.
Что будет если сравнить дату и строку?
При неявном сравнении даты и строки (например, КОГДА ДатаДокумента = "01.01.2023") 1С попытается преобразовать строку в дату по текущим региональным настройкам. Если формат строки не совпадёт с системным (например, в системе установлен формат ММ.ДД.ГГГГ, а в строке ДД.ММ.ГГГГ), условие вернёт ЛОЖЬ даже при визуальном совпадении дат.
4. Вложенные условия и оптимизация производительности
Конструкцию КОГДА можно вкладывать друг в друга, но это может существенно замедлить выполнение запроса. Правила оптимизации:
- 🔍 Порядок условий: Размещайте наиболее вероятные условия в начале — это ускорит выход из конструкции.
- 🧹 Избегайте дублирования: Если одно условие проверяется несколько раз, вынесите его в отдельное выражение с
ВЫРАЗИТЬ. - 📊 Агрегатные функции: Не используйте
СУММА()илиКОЛИЧЕСТВО()внутри КОГДА — это приведёт к полному сканированию таблицы.
Пример оптимизированного вложенного условия:
ВЫБРАТЬ
КОГДА ВидДокумента = ЗНАЧЕНИЕ(Справочник.ВидыДокументов.ЗаказПокупателя)
ТОГДА КОГДА СуммаДокумента > 50000 ТОГДА "Крупный заказ"
ИНАЧЕ "Мелкий заказ"
КОГДА ВидДокумента = ЗНАЧЕНИЕ(Справочник.ВидыДокументов.Реализация)
ТОГДА "Реализация"
ИНАЧЕ "Прочее" КАК ТипОперации
Для сложных условий (более 5-7 проверок) рассмотрите возможность:
- 🔄 Вынесения логики в виртуальную таблицу.
- 📝 Использования временных таблиц с предварительной категоризацией.
☑️ Проверка оптимизации запроса с КОГДА
5. Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при работе с КОГДА. Рассмотрим топ-5 проблем:
- 🚫 Пропущенное ТОГДА: Забыв указать
ТОГДА, получите синтаксическую ошибку. Пример ошибочного кода:КОГДА Сумма > 1000 "Большая" -- Ошибка! - 🔄 Неявное приведение типов: Сравнение
КОГДА Дата = 0не имеет смысла — дата никогда не будет равна числу. - 📝 Длинные строки в результатах: Если в
ТОГДАуказать строку длиной > 255 символов, запрос упадёт с ошибкой переполнения. - 🔢 NULL в условиях: Условие
КОГДА Поле = NULLне сработает — нужно использоватьЕСТЬ NULL. - 🔍 Логические ошибки: В конструкции ниже второй
КОГДАникогда не выполнится:КОГДА Сумма > 100 ТОГДА "Больше 100"КОГДА Сумма > 50 ТОГДА "Больше 50" -- Недостижимо!
Для отладки сложных условий используйте:
- 🛠️ Консоль запросов в конфигураторе с выводом плана выполнения.
- 📋 Пошаговое тестирование: Проверяйте каждое условие отдельно.
⚠️ Внимание: В платформе 1С:Предприятие 8.3.20+ появилась возможность использоватьВЫРАЗИТЬ(КОГДА ...)как отдельное выражение вГДЕилиУПОРЯДОЧИТЬ ПО. В более ранних версиях это приводило к ошибке.
6. Практическое применение: категоризация и трансформация данных
Конструкция КОГДА незаменима для:
- 📊 Категоризации: Разделение клиентов по сегментам, товаров по ценовым группам.
- 🔄 Трансформации данных: Замена кодов на наименования, конвертация единиц измерения.
- 📅 Аналитики по периодам: Определение кварталов, сезонов, временных интервалов.
Пример категоризации клиентов по сумме покупок:
ВЫБРАТЬ
Клиент,
СУММА(СуммаДокумента) КАК ОбщаяСумма,
КОГДА СУММА(СуммаДокумента) > 1000000 ТОГДА "VIP"
КОГДА СУММА(СуммаДокумента) > 500000 ТОГДА "Премиум"
КОГДА СУММА(СуммаДокумента) > 100000 ТОГДА "Стандарт"
ИНАЧЕ "Новый" КАК КатегорияКлиента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Клиент В (&СписокКлиентов)
СГРУППИРОВАТЬ ПО
Клиент
Для трансформации данных часто комбинируют КОГДА с функциями:
- 🔢
ЗНАЧЕНИЕ()— для сравнения со справочниками. - 📅
НАЧАЛОПЕРИОДА()— для работы с датами. - 📊
ВЫБОР()— как альтернатива для простых замен.
Для ускорения запросов с категоризацией создайте предварительно заполненный справочник категорий и используйте соединение (ЛЕВОЕ СОЕДИНЕНИЕ) вместо вычисления КОГДА на лету.
7. Альтернативные подходы: когда КОГДА не оптимально
В некоторых случаях КОГДА уступает другим методам:
| Задача | Альтернатива | Когда использовать |
|---|---|---|
| Простая замена значений | ВЫБОР() | Если условий не больше 3-4 |
| Фильтрация данных | ГДЕ с логическими операторами | Если нужно только отобрать записи, а не трансформировать |
| Сложная логика | Виртуальные таблицы или временные таблицы | Если условий больше 10 или они динамические |
| Работа с иерархией | ПУТЬ() или УРОВЕНЬ() | Для справочников с иерархией |
Пример замены КОГДА на ВЫБОР():
-- Через КОГДА
ВЫБРАТЬ КОГДА Статус = 1 ТОГДА "Новый" ИНАЧЕ "Закрытый" КАК СтатусТекст
-- Через ВЫБОР (короче и быстрее)
ВЫБРАТЬ ВЫБОР(Статус, "Новый", "Закрытый") КАК СтатусТекст
Для динамических условий (например, когда список категорий хранится в справочнике) лучше использовать соединение:
ВЫБРАТЬ
Товар.Наименование,
Категории.Наименование КАК Категория
ИЗ
Справочник.Номенклатура КАК Товар
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КатегорииТоваров КАК Категории
ПО Товар.Категория = Категории.Ссылка
Конструкция КОГДА оптимальна для статичных условий с 4-10 вариантами. Для динамических данных или большого количества проверок используйте справочники и соединения.
FAQ: Частые вопросы по использованию КОГДА
Можно ли использовать КОГДА в разделе ГДЕ?
Да, но только в платформе 1С:Предприятие 8.3.20 и выше. Пример:
ВЫБРАТЬ
Наименование
ИЗ
Справочник.Номенклатура
ГДЕ
ВЫРАЗИТЬ(КОГДА Цена > 1000 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ) = ИСТИНА
В более ранних версиях это приведёт к ошибке.
Как сравнить несколько полей в одном КОГДА?
Используйте логические операторы И/ИЛИ внутри условия:
ВЫБРАТЬ
КОГДА (Дата >= &НачалоПериода И Дата <= &КонецПериода) И Сумма > 1000
ТОГДА "Актуальный крупный заказ"
ИНАЧЕ "Прочее" КАК Категория
Почему условие КОГДА Поле = NULL не работает?
В языке запросов 1С для проверки на NULL используется оператор ЕСТЬ NULL:
ВЫБРАТЬ
КОГДА Поле ЕСТЬ NULL ТОГДА "Пустое"
ИНАЧЕ "Заполнено"
Можно ли использовать КОГДА с агрегатными функциями?
Технически можно, но это неэффективно. Пример:
ВЫБРАТЬ
КОГДА СУММА(Количество) > 100 ТОГДА "Много"
ИНАЧЕ "Мало" КАК Итог
ИЗ
Документ.ПоступлениеТоваров
Такой запрос выполнит полное сканирование таблицы. Лучше использовать ГРУППИРОВКА с HAVING.
Как отладить сложный запрос с вложенными КОГДА?
Разбейте запрос на части:
- Проверьте каждое условие отдельно в консоли запросов.
- Используйте
ПОМЕСТИТЬдля сохранения промежуточных результатов. - Включите вывод плана выполнения (
ОБЪЯСНИТЬ).
Пример с ПОМЕСТИТЬ:
ПОМЕСТИТЬ ВТ_Промежуточный
ВЫБРАТЬ
КОГДА Сумма > 1000 ТОГДА "Большой" ИНАЧЕ "Маленький" КАК Размер
ИЗ
Документ.Заказы;
ВЫБРАТЬ *
ИЗ
ВТ_Промежуточный