Работа с запросами в 1С:Предприятие часто требует гибких инструментов для фильтрации и трансформации данных. Одной из самых мощных, но порой недооценённых конструкций является множественный выбор с оператором КОГДА. Она позволяет заменять громоздкие объединения таблиц (ОБЪЕДИНИТЬ) или вложенные запросы (В) на компактный и читаемый код. Однако неправильное использование этой конструкции может привести к ошибкам выполнения, снижению производительности или некорректным результатам.
В этой статье мы разберём не только базовый синтаксис ВЫБРАТЬ ... КОГДА, но и нюансы работы с условной логикой в запросах, оптимизацию для больших баз данных, а также типичные ошибки, которые допускают даже опытные разработчики. Особое внимание уделим различиям между КОГДА и альтернативными подходами — когда стоит выбирать именно этот инструмент, а когда лучше отказаться от него в пользу других механизмов 1С.
Что такое множественный выбор в запросах 1С и зачем он нужен
Конструкция КОГДА ... ТОГДА ... ИНАЧЕ в языке запросов 1С аналогична оператору CASE WHEN в SQL. Она позволяет динамически формировать значения полей в результате запроса на основе условий. Например, вместо того чтобы создавать несколько запросов или использовать сложные объединения, вы можете в одном запросе:
- 📊 Классифицировать данные (например, разделить клиентов на группы по объёму заказов)
- 🔄 Заменять значения (подставлять "Да"/"Нет" вместо
ИСТИНА/ЛОЖЬ) - 📈 Вычислять производные поля (например, рассчитывать скидку в зависимости от категории товара)
- 🔍 Фильтровать данные по сложным условиям без дополнительных соединений таблиц
Главное преимущество КОГДА — это сокращение количества обращений к базе данных. Вместо того чтобы выполнять несколько запросов и потом объединять их результаты на стороне 1С, вы получаете готовый набор данных за один проход. Это особенно критично для крупных баз, где каждый лишний запрос может замедлять работу системы.
Синтаксис конструкции КОГДА в запросах 1С
Базовый синтаксис выглядит так:
ВЫБРАТЬ
КОГДА Условие1 ТОГДА Значение1
КОГДА Условие2 ТОГДА Значение2
...
ИНАЧЕ ЗначениеПоУмолчанию
КОНЕЦ КАК ПолеРезультата
Разберём ключевые элементы:
- 🔹
КОГДА Условие ТОГДА Значение— пара "условие-результат". Условие может быть любым логическим выражением, поддерживаемым в запросах (сравнения, функции, подзапросы). - 🔹
ИНАЧЕ— необязательный блок, который срабатывает, если ни одно из условий не выполнено. Если его опустить, результат будетNULL. - 🔹
КАК ПолеРезультата— присваивает имя столбцу в результате запроса.
Пример простого использования:
ВЫБРАТЬ
КОГДА Справочник.Клиенты.Категория = "VIP" ТОГДА "Приоритетный"
КОГДА Справочник.Клиенты.СуммаЗаказов > 100000 ТОГДА "Крупный"
ИНАЧЕ "Стандартный"
КОНЕЦ КАК ТипКлиента,
Справочник.Клиенты.Наименование КАК Клиент
ИЗ
Справочник.Клиенты КАК Справочник.Клиенты
Если в условии КОГДА используете сравнение с NULL, используйте конструкцию ЗНАЧЕНИЕ ЗАПОЛНЕНО(), а не просто = NULL. Последнее не сработает корректно!
Практические примеры использования КОГДА
Рассмотрим реальные сценарии, где КОГДА позволяет решить задачи элегантно и эффективно.
1. Категоризация данных
Допустим, нужно разделить товары на группы по остаткам на складе:
ВЫБРАТЬ
КОГДА ОстаткиТоваров.Количество = 0 ТОГДА "Нет в наличии"
КОГДА ОстаткиТоваров.Количество < 10 ТОГДА "Мало"
КОГДА ОстаткиТоваров.Количество >= 100 ТОГДА "Много"
ИНАЧЕ "Среднее количество"
КОНЕЦ КАК СтатусОстатка,
ОстаткиТоваров.Товар КАК Товар
ИЗ
РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
2. Замена булевых значений на текст
Часто в отчётах требуется показывать не ИСТИНА/ЛОЖЬ, а "Да/Нет":
ВЫБРАТЬ
КОГДА Документ.ЗаказКлиента.Оплачен ТОГДА "Да"
ИНАЧЕ "Нет"
КОНЕЦ КАК СтатусОплаты,
Документ.ЗаказКлиента.Номер КАК НомерЗаказа
ИЗ
Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
3. Расчёт скидок по условиям
Можно динамически назначать скидку в зависимости от суммы заказа:
ВЫБРАТЬ
КОГДА Документ.ЗаказКлиента.СуммаДокумента > 50000 ТОГДА 0.15
КОГДА Документ.ЗаказКлиента.СуммаДокумента > 20000 ТОГДА 0.10
КОГДА Документ.ЗаказКлиента.СуммаДокумента > 10000 ТОГДА 0.05
ИНАЧЕ 0
КОНЕЦ КАК РазмерСкидки,
Документ.ЗаказКлиента.Контрагент КАК Клиент
ИЗ
Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
Как избежать ошибки "Тип не совпадает" в КОГДА
Если в разных ветках КОГДА возвращаются значения разных типов (например, строка и число), 1С выдаст ошибку. Все результаты должны быть приведёны к одному типу, например, с помощью СТРОКА() или ЧИСЛО().
Оптимизация запросов с КОГДА: что нужно знать
Хотя КОГДА упрощает код, его неправильное использование может привести к замедлению выполнения запроса. Вот ключевые правила оптимизации:
- 🚀 Избегайте сложных условий в КОГДА. Если условие включает подзапросы или функции (например,
НАЙТИ()), запрос будет выполняться дольше. По возможности выносите такие проверки в отдельные соединения таблиц. - 📉 Минимизируйте количество веток КОГДА. Чем их больше, тем сложнее план выполнения запроса. Если условий больше 5–7, рассмотрите альтернативные подходы.
- 🔄 Используйте индексируемые поля в условиях. Если в условии участвует поле, по которому нет индекса, СУБД будет сканировать всю таблицу.
- 📊 Тестируйте производительность. Для больших баз данных сравните время выполнения запроса с
КОГДАи альтернативными методами (например,ОБЪЕДИНИТЬ).
Пример неоптимального запроса (сложное условие в каждой ветке):
ВЫБРАТЬ
КОГДА НАЙТИ(Документ.ЗаказКлиента.Комментарий, "Срочно") > 0 ТОГДА "Приоритет"
КОГДА Документ.ЗаказКлиента.Дата < ТЕКУЩАЯДАТА() - 30 ТОГДА "Просрочен"
ИНАЧЕ "Обычный"
КОНЕЦ КАК Статус
Оптимизированный вариант (предварительный расчёт в подзапросе):
ВЫБРАТЬ
КОГДА СрочныйЗаказ ТОГДА "Приоритет"
КОГДА ПросроченныйЗаказ ТОГДА "Просрочен"
ИНАЧЕ "Обычный"
КОНЕЦ КАК Статус
ИЗ (
ВЫБРАТЬ
НАЙТИ(Документ.ЗаказКлиента.Комментарий, "Срочно") > 0 КАК СрочныйЗаказ,
Документ.ЗаказКлиента.Дата < ТЕКУЩАЯДАТА() - 30 КАК ПросроченныйЗаказ
ИЗ
Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
) КАК Подзапрос
Конструкция КОГДА не заменяет индексы. Если запрос тормозит, сначала проверьте наличие индексов на полях, участвующих в условиях.
Типичные ошибки при работе с КОГДА и как их избежать
Даже опытные разработчики допускают ошибки при использовании КОГДА. Вот наиболее распространённые:
| Ошибка | Причина | Как исправить |
|---|---|---|
| Ошибка типа "Тип не совпадает" | В разных ветках КОГДА возвращаются значения разных типов (строка и число). |
Приведите все результаты к одному типу с помощью СТРОКА(), ЧИСЛО(). |
| Запрос выполняется слишком долго | Сложные условия в каждой ветке КОГДА или отсутствие индексов. |
Упростите условия или используйте соединения таблиц вместо КОГДА. |
Некорректный результат для NULL |
Условие КОГДА Поле = NULL не срабатывает (в SQL сравнение с NULL всегда возвращает NULL). |
Используйте ЗНАЧЕНИЕ ЗАПОЛНЕНО(Поле). |
| Ошибка "Поле не найдено" | В условии КОГДА используется поле, не включённое в ИЗ или СОЕДИНИТЬ. |
Проверьте наличие поля в источниках данных запроса. |
Пример ошибки с NULL:
-- НЕПРАВИЛЬНО (не сработает для NULL):
ВЫБРАТЬ
КОГДА Справочник.Контрагенты.ИНН = NULL ТОГДА "Без ИНН"
ИНАЧЕ "С ИНН"
КОНЕЦ КАК СтатусИНН
-- ПРАВИЛЬНО:
ВЫБРАТЬ
КОГДА НЕ ЗНАЧЕНИЕ ЗАПОЛНЕНО(Справочник.Контрагенты.ИНН) ТОГДА "Без ИНН"
ИНАЧЕ "С ИНН"
КОНЕЦ КАК СтатусИНН
Все ветки КОГДА возвращают значения одного типа|Условия не содержат сравнений с NULL без ЗНАЧЕНИЕ ЗАПОЛНЕНО()|Поля в условиях существуют в источниках данных|Для больших таблиц проверены индексы-->
Альтернативы КОГДА: когда лучше использовать другие методы
Хотя КОГДА удобен, в некоторых случаях лучше выбрать альтернативные подходы:
- 🔀
ОБЪЕДИНИТЬ(UNION) — если данные нужно брать из разных таблиц или запросов. Например, для объединения остатков по нескольким складам. - 🔗
СОЕДИНИТЬ(JOIN) — если условия зависят от данных из связанных таблиц. Например, проверка статуса клиента из справочника. - 📝 Виртуальные таблицы — если логика слишком сложна для
КОГДА, но нужны агрегированные данные (например, остатки с разрезами). - 🖥️ Обработка на стороне 1С — если условия динамические и зависят от пользовательского ввода, иногда проще получить данные запросом, а затем обработать их в коде.
Пример, где ОБЪЕДИНИТЬ эффективнее:
-- Вместо:
ВЫБРАТЬ
КОГДА ТипДокумента = "ЗаказКлиента" ТОГДА Документ.ЗаказКлиента.Сумма
КОГДА ТипДокумента = "Реализация" ТОГДА Документ.Реализация.Сумма
КОНЕЦ КАК Сумма
ИЗ (...)
-- Лучше:
ВЫБРАТЬ Документ.ЗаказКлиента.Сумма КАК Сумма
ИЗ Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
ОБЪЕДИНИТЬ
ВЫБРАТЬ Документ.Реализация.Сумма КАК Сумма
ИЗ Документ.Реализация КАК Документ.Реализация
Если в запросе с КОГДА используется более 3–4 условий, рассмотрите возможность вынесения логики в отдельную таблицу-справочник с предопределёнными значениями.
Расширенные возможности: вложенные КОГДА и работа с агрегатами
Конструкцию КОГДА можно вкладывать друг в друга, а также комбинировать с агрегатными функциями (СУММА, МАКСИМУМ и т. д.). Это позволяет решать сложные задачи в одном запросе.
1. Вложенные КОГДА
Пример: классификация клиентов по двум критериям (сумма заказов и регион):
ВЫБРАТЬ
КОГДА Справочник.Клиенты.Регион = "Москва"
ТОГДА КОГДА Справочник.Клиенты.СуммаЗаказов > 100000 ТОГДА "VIP Москва"
ИНАЧЕ "Стандарт Москва"
КОГДА Справочник.Клиенты.Регион = "Санкт-Петербург"
ТОГДА КОГДА Справочник.Клиенты.СуммаЗаказов > 50000 ТОГДА "VIP СПб"
ИНАЧЕ "Стандарт СПб"
ИНАЧЕ "Региональный клиент"
КОНЕЦ КАК КатегорияКлиента
2. КОГДА с агрегатными функциями
Можно динамически рассчитывать показатели. Например, определить "лидера продаж" по категориям:
ВЫБРАТЬ
Номенклатура.Категория КАК Категория,
КОГДА СУММА(Документ.Реализация.Количество) > 1000 ТОГДА "Хит продаж"
КОГДА СУММА(Документ.Реализация.Количество) > 500 ТОГДА "Популярный"
ИНАЧЕ "Обычный"
КОНЕЦ КАК СтатусТовара
ИЗ
Документ.Реализация КАК Документ.Реализация
СОЕДИНИТЬ Справочник.Номенклатура КАК Номенклатура
ПО Документ.Реализация.Номенклатура = Номенклатура.Ссылка
СГРУППИРОВАТЬ ПО
Номенклатура.Категория
Важно: при использовании КОГДА с агрегатами учитывайте, что:
- 📌 Условия в
КОГДАприменяются после группировки, а не до неё. - 📌 Если в условии нужны данные до агрегации (например, проверка каждой строки), используйте подзапрос.
Вложенные КОГДА ухудшают читаемость кода. Если логика становится слишком сложной, разбейте запрос на несколько этапов или используйте временные таблицы.
FAQ: Ответы на частые вопросы о КОГДА в запросах 1С
Можно ли использовать КОГДА в секции ГДЕ?
Нет, конструкция КОГДА предназначена только для формирования полей в секции ВЫБРАТЬ. В секции ГДЕ используйте стандартные логические операторы (И, ИЛИ, НЕ). Однако можно эмулировать подобную логику с помощью В (подзапроса):
ВЫБРАТЬ ...
ГДЕ Ссылка В (
ВЫБРАТЬ Ссылка
ИЗ Документ.ЗаказКлиента
ГДЕ КОГДА Статус = "Оплачен" ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ
)
Но такой подход неэффективен — лучше переписать условие без КОГДА.
Как в КОГДА проверить несколько условий одновременно (аналог AND)?
Используйте логические операторы И, ИЛИ внутри условия КОГДА:
ВЫБРАТЬ
КОГДА (Документ.ЗаказКлиента.Сумма > 10000)
И (Документ.ЗаказКлиента.Дата > '2023-01-01') ТОГДА "Крупный новый заказ"
ИНАЧЕ "Другой заказ"
КОНЕЦ КАК ТипЗаказа
Почему запрос с КОГДА работает медленно на большой базе?
Причины могут быть следующими:
- Отсутствуют индексы на полях, участвующих в условиях
КОГДА. - Условия содержат функции (например,
НАЙТИ()), которые не могут использовать индексы. - Слишком много веток
КОГДА(оптимально — не более 5–7). - В условиях используются подзапросы.
Решение: упростите условия, добавьте индексы или разбейте запрос на несколько этапов.
Можно ли в КОГДА использовать данные из другой таблицы без соединения?
Нет, все поля в условиях КОГДА должны быть доступны в текущем контексте запроса. Если нужно использовать данные из другой таблицы, сначала выполните соединение (СОЕДИНИТЬ) или подзапрос.
Пример с соединением:
ВЫБРАТЬ
КОГДА Справочник.Контрагенты.Категория = "VIP"
И Документ.ЗаказКлиента.Сумма > 10000 ТОГДА "Приоритетный VIP"
ИНАЧЕ "Обычный"
КОНЕЦ КАК ТипЗаказа
ИЗ
Документ.ЗаказКлиента КАК Документ.ЗаказКлиента
СОЕДИНИТЬ Справочник.Контрагенты КАК Справочник.Контрагенты
ПО Документ.ЗаказКлиента.Контрагент = Справочник.Контрагенты.Ссылка
Как вернуть NULL в одной из веток КОГДА, если в других ветках возвращаются строки?
Нужно явно привести NULL к строковому типу с помощью ЗНАЧЕНИЕ(NULL) или СТРОКА(NULL), иначе будет ошибка типов:
ВЫБРАТЬ
КОГДА Условие1 ТОГДА "Значение1"
КОГДА Условие2 ТОГДА ЗНАЧЕНИЕ(NULL) -- Явное приведение к строке
ИНАЧЕ "Значение3"
КОНЕЦ КАК Результат