Работая с языком запросов платформы 1С:Предприятие, разработчики часто сталкиваются с необходимостью обработки данных прямо на уровне СУБД, не прибегая к циклам в коде. Для реализации условной логики, аналогичной оператору if..else в процедурном программировании, используется специальная конструкция ВЫБОР. Правильное использование этой конструкции позволяет существенно оптимизировать производительность отчетов и обработок данных.

Понимание синтаксиса ключевых слов КОГДА, ТОГДА и ИНАЧЕ является фундаментом для написания сложных аналитических запросов. Эта инструкция поможет вам освоить нюансы применения условных выражений, избежать распространенных ошибок типизации и писать эффективный код для платформы версии 8.3 и выше.

Прежде чем углубиться в детали, стоит отметить, что конструкция ВЫБОР возвращает единое значение, тип которого определяется правилами приведения типов данных 1С. Это означает, что все ветви условия должны возвращать совместимые типы, иначе вы получите ошибку выполнения или непредсказуемое поведение отчета.

Базовый синтаксис и структура конструкции

Конструкция условного выбора в языке запросов 1С имеет строгую иерархическую структуру. Она начинается с ключевого слова ВЫБОР и завершается словом КОНЕЦ. Внутри блока располагаются условия, которые проверяются последовательно сверху вниз. Как только найдено первое истинное условие, выполняется соответствующая ветвь, и дальнейшая проверка прекращается.

Каждое условие состоит из пары ключевых слов: КОГДА задает логическое выражение для проверки, а ТОГДА определяет значение, которое будет возвращено при истинности этого выражения. Если ни одно из условий не выполнено, управление передается блоку ИНАЧЕ, если он присутствует в запросе.

Синтаксис выглядит следующим образом:

ВЫБОР

КОГДА Условие1 ТОГДА Значение1

КОГДА Условие2 ТОГДА Значение2

ИНАЧЕ ЗначениеПоУмолчанию

КОНЕЦ

Она должна быть частью поля выборки или условия в секции ГДЕ.

Рассмотрим простой пример, где мы присваиваем текстовое описание статусу документа на основе его булевого поля:

ВЫБОР

КОГДА Документ.Проведен ТОГДА "Проведен"

ИНАЧЕ "Не проведен"

КОНЕЦ КАК СтатусТекст

Здесь мы формируем новую колонку в результате запроса, содержащую человекочитаемое значение.

💡

Используйте псевдонимы (КАК) для полей с конструкцией ВЫБОР, чтобы результат запроса имел понятное имя в таблице значений или отчете.

Использование в секции ВЫБРАТЬ для трансформации данных

Наиболее частый сценарий применения — трансформация данных непосредственно в списке выборки. Это позволяет избежать дополнительных проходов по данным в цикле на стороне клиента. Вы можете создавать вычисляемые поля, которые зависят от значений других полей той же записи.

Например, при формировании отчета по продажам часто требуется классифицировать товары по категориям маржинальности. Вместо того чтобы выбирать все данные и сортировать их в коде, логичнее сделать это в запросе:

ВЫБРАТЬ

Продажи.Номенклатура,

Продажи.Сумма,

ВЫБОР

КОГДА Продажи.Сумма > 100000 ТОГДА "Высокая"

КОГДА Продажи.Сумма > 50000 ТОГДА "Средняя"

ИНАЧЕ "Низкая"

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

ИЗ

Документ.РеализацияТоваровУслуг.Продажи КАК Продажи

Такой подход значительно ускоряет работу с большими объемами данных.

⚠️ Внимание: Порядок условий в конструкции ВЫБОР критически важен. Если вы поставите условие "Сумма > 50000" перед условием "Сумма > 100000", то второе условие никогда не выполнится, так как первое поглотит все значения больше 50 тысяч.

Также стоит учитывать производительность. Хотя база данных оптимизирует выполнение запросов, чрезмерно вложенные или сложные условия КОГДА могут замедлить формирование выборки. Старайтесь держать логику максимально простой и понятной.

📊 Как часто вы используете конструкцию ВЫБОР в запросах?
Ежедневно
Несколько раз в неделю
Редко
Никогда не использовал

Применение в условиях секции ГДЕ

Конструкция ВЫБОР может использоваться не только для формирования полей, но и для динамического формирования условий отбора. Это особенно полезно, когда критерий фильтрации зависит от значения другого поля или параметра запроса.

Представьте ситуацию, когда нужно отобрать документы, но правила отбора различаются для разных видов операций. Для одного вида важен статус, для другого — дата. Используя ВЫБОР в секции ГДЕ, мы можем унифицировать условие:

ГДЕ

ВЫБОР

КОГДА Документ.ВидОперации = "Услуга" ТОГДА Документ.Дата > &НачалоПериода

КОГДА Документ.ВидОперации = "Товар" ТОГДА Документ.Проведен = ИСТИНА

ИНАЧЕ ЛОЖЬ

КОНЕЦ

В данном примере запрос вернет только те строки, где результат вычисления конструкции будет истинным.

Такой прием позволяет избежать написания громоздких условий с множеством скобок и операторов ИЛИ. Однако будьте осторожны: если условие внутри ТОГДА возвращает не булево значение, а, например, число или строку, это может привести к ошибке сравнения в секции ГДЕ.

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

Группировка и агрегация с условной логикой

Одной из самых мощных возможностей конструкции ВЫБОР является ее использование внутри агрегатных функций, таких как СУММА, КОЛИЧЕСТВО или МИНИМУМ. Это позволяет выполнять так называемую "сводную группировку" (pivot) прямо в запросе, получая несколько итоговых колонок за один проход.

Классический пример — подсчет суммы продаж по разным менеджерам в разрезе одного запроса, где каждый менеджер становится отдельной колонкой:

ВЫБРАТЬ

Продажи.Контрагент,

СУММА(ВЫБОР КОГДА Продажи.Менеджер = &Менеджер1 ТОГДА Продажи.Сумма ИНАЧЕ 0 КОНЕЦ) КАК СуммаМен1,

СУММА(ВЫБОР КОГДА Продажи.Менеджер = &Менеджер2 ТОГДА Продажи.Сумма ИНАЧЕ 0 КОНЕЦ) КАК СуммаМен2

ИЗ

Документ.РеализацияТоваровУслуг.Продажи КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Контрагент

Обратите внимание на использование 0 в ветке ИНАЧЕ. Это критически важно для корректной работы функции СУММА.

☑️ Правила агрегации с ВЫБОР

Выполнено: 0 / 4

Если в ветке ИНАЧЕ указать NULL (или не указать её вовсе, что равносильно NULL), функция СУММА проигнорирует эти строки, что в данном конкретном случае сводной таблицы может быть неверно, если нам нужно видеть нули вместо пустот. Однако для функции СРЕДНЕЕ использование NULL может быть предпочтительнее, чтобы не занижать средний показатель нулевыми значениями.

Агрегатная функция Рекомендуемое значение ИНАЧЕ Причина
СУММА 0 Чтобы строки учитывались как ноль, а не игнорировались
СРЕДНЕЕ NULL Чтобы исключить значения из расчета среднего арифметического
МИНИМУМ / МАКСИМУМ NULL Чтобы не исказить экстремальные значения нулем или пустой строкой
КОЛИЧЕСТВО 1 (внутри суммы) или NULL Зависит от логики: считать все строки или только подходящие

Использование таких конструкций требует внимательности к типам данных. Убедитесь, что числовые значения не смешиваются со строковыми внутри одной агрегатной функции.

Типизация и проблемы приведения данных

Платформа 1С:Предприятие строго следит за типами данных в запросах. Самая распространенная ошибка при работе с конструкцией ВЫБОР — попытка вернуть разные типы данных в разных ветках условия. Например, вернуть Число в одной ветке и Строку в другой.

В таких случаях система пытается привести типы к общему знаменателю. Если это невозможно (например, Дата и Булево), вы получите ошибку: "Неправильный тип аргумента". Даже если приведение возможно (например, Число и Строка), результат может быть неожиданным для пользователя отчета.

⚠️ Внимание: Никогда не полагайтесь на автоматическое приведение типов в сложных отчетах. Явно преобразуйте данные с помощью функций ЕСТЬNULL, СТРОКА или ЧИСЛО внутри веток ТОГДА.

Особую сложность представляет работа с типом NULL. В 1С NULL — это не значение, а отсутствие значения. Если одна ветка возвращает конкретное число, а другая NULL, результирующий тип поля будет содержать Число и NULL. Это допустимо, но может повлиять на сортировку и группировку.

Что такое неопределенный тип?

Если ветки ВЫБОР возвращают совершенно несовместимые типы, которые нельзя привести друг к другу, компилятор запросов выдаст ошибку. Например, попытка вернуть СправочникСсылка в одной ветке и Число в другой приведет к сбою.

Для избежания проблем рекомендуется явно указывать тип возвращаемого значения. Если логика требует возврата разных сущностей, подумайте о разделении запроса или использовании временных таблиц.

Вложенные конструкции и оптимизация

Конструкция ВЫБОР поддерживает вложенность. Вы можете поместить одну конструкцию ВЫБОР внутрь ветки ТОГДА другой. Это позволяет реализовывать сложные деревья решений. Однако глубина вложенности не должна быть чрезмерной, так как это ухудшает читаемость кода и может затруднить работу оптимизатора запросов.

Пример вложенной логики:

ВЫБОР

КОГДА ТипДокумента = "Заказ" ТОГДА

ВЫБОР

КОГДА Статус = "Новый" ТОГДА "Обработка"

ИНАЧЕ "Архив"

КОНЕЦ

ИНАЧЕ "Прочее"

КОНЕЦ

Такой код эквивалентен вложенным условиям if в обычном программировании.

С точки зрения производительности, база данных (MS SQL, PostgreSQL или встроенная) вычисляет конструкцию ВЫБОР для каждой строки результата. Если условий очень много, это может создать нагрузку на процессор сервера. В таких случаях иногда эффективнее сделать несколько простых запросов и объединить их, чем один сложный с гигантским ВЫБОР.

💡

Оптимальная глубина вложенности ВЫБОР — не более 2-3 уровней. Если логика сложнее, рассмотрите возможность вычисления части условий во временной таблице.

Также стоит помнить о кэшировании планов выполнения запросов. Слишком динамичные конструкции, зависящие от множества параметров, могут препятствовать эффективному кэшированию плана запроса сервером СУБД.

Частые ошибки и способы их устранения

При написании запросов с условной логикой разработчики часто допускают типовые ошибки. Одна из них — забытое ключевое слово КОНЕЦ. Без него парсер запросов не сможет определить границу конструкции и выдаст синтаксическую ошибку.

Другая распространенная проблема — использование конструкции ВЫБОР в местах, где это не предусмотрено синтаксисом, например, в секции ИЗ или ИЗ (для указания источников данных). Конструкция допустима только там, где ожидается выражение: в полях выборки, в условиях ГДЕ, ИМЕЮЩИЕ, УПОРЯДОЧИТЬ ПО.

Также стоит быть внимательным при работе с NULL. Сравнение КОГДА Поле = NULL всегда вернет ЛОЖЬ. Для проверки на неопределенное значение необходимо использовать конструкцию КОГДА Поле ЕСТЬ NULL.

⚠️ Внимание: Интерфейсы и поведение конструктора запросов могут меняться в новых версиях платформы 1С. Всегда проверяйте актуальность синтаксических подсказок в вашей конкретной конфигурации и версии платформы.

Для отладки сложных условий используйте вывод промежуточных полей. Добавьте поле с результатом ВЫБОР в результат запроса, чтобы визуально убедиться в корректности логики перед тем, как использовать его для агрегации или фильтрации.

Лайфхак для отладки

Если запрос не выполняется, попробуйте закомментировать часть условий в ВЫБОР, оставив только одно. Это поможет локализовать ошибку в конкретной ветке логики.

Можно ли использовать ВЫБОР в параметрах запроса?

Нет, конструкция ВЫБОР является частью языка запросов и исполняется на стороне базы данных или движка запросов 1С. Параметры запроса (обозначаемые символом &) передаются из кода 1С до начала выполнения запроса. Однако вы можете использовать результат ВЫБОР для формирования значений, которые затем будут использованы в других запросах.

В чем разница между ВЫБОР и функцией ЕСТЬNULL?

Функция ЕСТЬNULL(Значение, Замена) является частным случаем конструкции ВЫБОР. Она проверяет только одно условие: является ли значение NULL. Конструкция ВЫБОР универсальна и позволяет проверять любые логические выражения, а не только наличие пустого значения.

Как вернуть NULL в ветке ИНАЧЕ?

Чтобы явно вернуть неопределенное значение, просто не указывайте значение после слова ИНАЧЕ перед словом КОНЕЦ, либо используйте ключевое слово NULL, если синтаксис конкретной версии платформы это позволяет. Чаще всего достаточно написать ИНАЧЕ NULL КОНЕЦ.

Влияет ли порядок условий КОГДА на скорость запроса?

Да, влияет. Так как проверка идет последовательно, наиболее вероятные условия следует размещать в начале конструкции. Это позволит базе данных раньше завершать проверку для большинства строк, экономя процессорное время.