Разработка и Конфигурация · 10 мин
Конструкция ВЫБОР КОГДА ТОГДА в запросах 1С: синтаксис и практика
Как работает конструкция ВЫБОР КОГДА ТОГДА ИНАЧЕ КОНЕЦ в запросах 1С: синтаксис, примеры с условиями, типичные ошибки, ограничения и альтернативы.
Конструкция ВЫБОР КОГДА ТОГДА — это аналог условного оператора «если… то… иначе» внутри языка запросов 1С. Она позволяет вернуть разные значения в одном поле в зависимости от условия, не прибегая к нескольким запросам и без постобработки в коде. Типичные задачи: вывести текстовое представление статуса документа, подставить значение по умолчанию вместо NULL, разделить данные на категории для отчёта.
Конструкция полностью соответствует оператору CASE в стандарте SQL и компилируется платформой в него при передаче запроса в СУБД. Это значит, что вычисление происходит на стороне сервера базы данных, а не в памяти приложения, — производительность при корректном использовании не страдает. Ниже разобраны синтаксис, типовые сценарии, ограничения и ошибки, которые чаще всего встречаются на практике.
Синтаксис конструкции и базовый пример
Полная форма записи выглядит так: после ключевого слова ВЫБОР перечисляются пары КОГДА <условие> ТОГДА <результат>, затем необязательная ветвь ИНАЧЕ и завершающее слово КОНЕЦ. Условий может быть сколько угодно — платформа проверяет их сверху вниз и возвращает результат первого истинного условия.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
ВЫБОР
КОГДА Остатки.КоличествоОстаток ЕСТЬ NULL
ТОГДА 0
КОГДА Остатки.КоличествоОстаток < 10
ТОГДА Остатки.КоличествоОстаток
ИНАЧЕ 10
КОНЕЦ КАК ОстатокДляЗаказа
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
Порядок условий имеет значение: проверка идёт последовательно, и как только одно из условий выполнено, остальные ветви не анализируются. Поэтому более частные условия ставят выше, а общие — ниже. Если ни одно условие не сработало и ветви ИНАЧЕ нет, поле получит значение NULL, что часто становится причиной неожиданных пустых ячеек в отчётах.
Типовые сценарии использования
Самая частая задача — замена NULL на значение по умолчанию. При левом соединении с виртуальными таблицами остатков или оборотов отсутствующие записи дают NULL в числовых полях, и любые арифметические операции с ними тоже вернут NULL. Обёртка в ВЫБОР КОГДА … ЕСТЬ NULL ТОГДА 0 решает проблему, хотя функция ЕСТЬNULL() короче и предпочтительнее именно для этой цели.
Вторая типовая задача — категоризация данных для отчётов. Например, разбить контрагентов на группы по сумме долга, а документы — по статусу проведения. Текстовое представление при этом формируется прямо в запросе, и в коде остаётся только вывести результат.
ВЫБОР
КОГДА Долг.СуммаОстаток > 100000
ТОГДА "Критический"
КОГДА Долг.СуммаОстаток > 0
ТОГДА "Есть задолженность"
ИНАЧЕ "Долга нет"
КОНЕЦ КАК СтатусДолга
Третий сценарий — выбор источника значения. Например, взять цену из индивидуального договора, а если её нет — из общего прайса. Это позволяет реализовать каскадную логику «сначала приоритетный источник, потом резервный» одним полем запроса.
Составные условия и логические операторы
Внутри КОГДА допустимы любые логические выражения, которые разрешены в секции ГДЕ: сравнения, И, ИЛИ, НЕ, проверки В ИЕРАРХИИ, В списке значений, ПОДОБНО. Это позволяет строить сложные ветвления без вложенных конструкций ВЫБОР.
КОГДА Заказ.Проведен
И НЕ Заказ.ПометкаУдаления
И Заказ.СуммаДокумента > 0
ТОГДА "Активный"
При комбинировании И и ИЛИ используйте скобки явно — приоритет операторов в запросах тот же, что в обычной логике (И выше ИЛИ), но явная группировка защищает от ошибок при последующем редактировании запроса другими разработчиками.
Вложенные конструкции ВЫБОР
Конструкции ВЫБОР можно вкладывать друг в друга: результатом ветви ТОГДА или ИНАЧЕ может быть новый ВЫБОР. Это удобно, когда логика естественно делится на два уровня — например, сначала определяется тип контрагента, а внутри каждого типа — своя шкала категорий.
ВЫБОР
КОГДА Контрагент.ЮрФизЛицо = ЗНАЧЕНИЕ(Перечисление.ЮрФизЛицо.ЮрЛицо)
ТОГДА ВЫБОР
КОГДА Контрагент.ИНН = ""
ТОГДА "Юрлицо без ИНН"
ИНАЧЕ "Юрлицо"
КОНЕЦ
ИНАЧЕ "Физлицо"
КОНЕЦ КАК КатегорияКонтрагента
Глубокая вложенность ухудшает читаемость и усложняет отладку. Если уровней больше двух-трёх, практичнее перенести логику в несколько отдельных полей запроса или в пакет запросов с промежуточной временной таблицей, где категория вычисляется пошагово.
Типы данных в ветвях: требования и подводные камни
Все ветви ТОГДА и ИНАЧЕ должны возвращать значения совместимых типов. Смешивание строки и числа в одном поле приведёт либо к ошибке выполнения запроса, либо к неявному приведению с непредсказуемым результатом — поведение зависит от используемой СУБД. Платформа не всегда перехватывает такую ошибку на этапе проверки запроса в консоли.
Отдельная тонкость — строки разной длины. Если одна ветвь возвращает строку из реквизита с ограничением 10 символов, а другая — литерал длиннее, СУБД может обрезать результат до длины первой ветви. Надёжное решение — привести все строковые ветви к одному типу через ВЫРАЗИТЬ(… КАК Строка(150)).
Со ссылочными типами ситуация похожая: если одна ветвь возвращает ссылку на справочник «Номенклатура», а другая — на «Контрагенты», поле станет составного типа. Это допустимо, но замедляет работу с полем и запрещает использование его в соединениях без дополнительного приведения.
Производительность и ограничения
Сама по себе конструкция ВЫБОР почти бесплатна для СУБД — это простое ветвление по уже выбранной строке. Проблемы начинаются, когда в условиях участвуют поля из дополнительных соединений: каждое такое соединение умножает стоимость запроса. Если ветвление требует данных из трёх-четырёх дополнительных таблиц, стоит рассмотреть предварительную сборку этих данных во временную таблицу.
Конструкцию ВЫБОР нельзя использовать в параметрах виртуальных таблиц — там допустимы только простые условия сравнения. В секции ГДЕ и в условиях соединений ВЫБОР использовать можно, но делать этого не стоит: такие условия не используют индексы, и СУБД вынуждена сканировать таблицу целиком. Фильтрацию всегда лучше выражать прямыми условиями.
Альтернативы: ЕСТЬNULL и выбор в СКД
Для единственной задачи — подстановки значения вместо NULL — существует специальная функция ЕСТЬNULL(Поле, ЗначениеПоУмолчанию). Она короче, читается легче и однозначно передаёт намерение. ВЫБОР оправдан только тогда, когда условий больше одного или условие сложнее проверки на NULL.
В отчётах на СКД часть логики ВЫБОР можно вынести в вычисляемые поля или выражения представления. Это уместно, когда ветвление нужно только для отображения, а сами данные в запросе остаются «сырыми». Однако если категория участвует в группировках и отборах, вычислять её надо именно в запросе, иначе СКД не сможет по ней сгруппировать.
Сравнение вариантов
Несколько условий, сложная логика, категоризация. Универсально, но многословно для простых случаев
Только замена NULL значением по умолчанию. Короче и понятнее, но не умеет ничего другого
Ветвление только для отображения в отчёте. Не подходит для группировок и отборов
Крайний случай: логика слишком сложна для запроса. Замедляет обработку больших выборок
Как проверить корректность результата
Отладку удобно начинать в консоли запросов: выполните запрос без конструкции ВЫБОР, выведя исходные поля условий, и убедитесь, что данные выглядят так, как ожидается. Затем добавьте ВЫБОР и сравните: для каждой строки результат должен соответствовать тому условию, которое должно было сработать.
Особое внимание уделите строкам, где исходные поля содержат NULL, и граничным значениям — ровно на пороге условия сравнения. Именно там чаще всего обнаруживаются ошибки порядка ветвей и нестрогих сравнений.
Как проверить результат
Получили значение из ветви ИНАЧЕ или обработки ЕСТЬ NULL
NULL просочился в итоговое поле
Попали в ожидаемую ветвь согласно строгости сравнения
Граница отнесена не к той категории
Одинаковый тип во всех строках результата
Смешение типов или обрезанные строки
Если запрос используется в отчёте СКД, дополнительно проверьте итоги по группировкам: категория, вычисленная через ВЫБОР, должна корректно группироваться, а не распадаться на отдельные строки из-за различий в представлении.
Частые вопросы
Можно ли использовать ВЫБОР в секции ГДЕ?
Технически синтаксис это допускает, но делать так не следует: условие с ВЫБОР не может использовать индексы, и СУБД будет сканировать всю таблицу. Фильтрацию выражайте прямыми сравнениями полей, а ВЫБОР оставьте для списка выбираемых полей.
Что вернёт ВЫБОР, если ни одно условие не выполнилось и ИНАЧЕ нет?
Поле получит значение NULL. Это частый источник ошибок: NULL не равен нулю и пустой строке, любые сравнения и арифметика с ним дают NULL. Если значение по умолчанию подразумевается — всегда пишите ветвь ИНАЧЕ явно.
Чем ВЫБОР отличается от ЕСТЬNULL?
ЕСТЬNULL решает одну задачу — подстановку значения вместо NULL — и делает это короче. ВЫБОР универсальнее: проверяет произвольные условия и поддерживает несколько ветвей. Для простой замены NULL используйте ЕСТЬNULL, для логики с условиями — ВЫБОР.
Можно ли в ТОГДА вернуть значение перечисления или ссылку?
Да, допустимы любые типы: примитивные, ссылки, перечисления через ЗНАЧЕНИЕ(Перечисление.Имя.Значение). Главное — чтобы все ветви возвращали совместимые типы, иначе получите ошибку выполнения или составной тип поля с сопутствующими ограничениями.
Влияет ли количество ветвей КОГДА на скорость запроса?
Практически нет: проверка условий выполняется для уже выбранной строки и стоит заметно дешевле чтения данных. На производительность влияют не сами ветви, а соединения и вложенные запросы, использованные внутри условий.
Как отладить сложный ВЫБОР с несколькими условиями?
Выведите рядом с результатом ВЫБОР все поля, участвующие в условиях, и выполните запрос в консоли. Для каждой строки будет видно, какое условие должно было сработать. Если логика запутана — временно разбейте её на несколько отдельных полей с простыми условиями.
Что важно запомнить
ВЫБОР КОГДА ТОГДА ИНАЧЕ КОНЕЦ — условное выражение в списке полей запроса. Всегда добавляйте ИНАЧЕ, следите за совместимостью типов ветвей и порядком условий. Для замены NULL используйте ЕСТЬNULL, а ВЫБОР не применяйте в ГДЕ и соединениях — это отключает индексы.