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