Разработка и Конфигурация · 12 мин
ВЫБОР КОГДА со ссылкой в запросах 1С: практическое руководство
Как использовать конструкцию ВЫБОР КОГДА со ссылками в запросах 1С: проверка типа ссылки, сравнение, ЗНАЧЕНИЕ, ВЫРАЗИТЬ и типичные ошибки с примерами кода.
Конструкция ВЫБОР КОГДА в языке запросов 1С — аналог оператора CASE в классическом SQL. Она позволяет вернуть разные значения в зависимости от условия прямо в тексте запроса, без постобработки выборки в коде. Одна из самых частых задач — работа со ссылками: определить тип документа, подставить конкретное значение справочника, заменить битую ссылку на понятную строку.
Особенность ссылок в том, что это составной тип данных. Ссылка может указывать на справочник, документ, план видов характеристик и другие объектные типы, поэтому платформа накладывает ограничения: нельзя напрямую сравнивать ссылки разных типов в одном поле, нельзя без приведения типа вернуть из разных веток КОГДА ссылки на разные объекты. Именно из-за этих нюансов у начинающих разработчиков запросы с ВЫБОР КОГДА и ссылками либо не выполняются, либо возвращают неожиданный результат.
Ниже разобраны рабочие сценарии: проверка типа ссылки, сравнение с конкретным значением, подстановка значений перечисления, обработка составных полей и типичные ошибки с пояснением, почему они возникают и как их исправить.
Базовый синтаксис ВЫБОР КОГДА в запросе 1С
Полная форма конструкции выглядит так: после ключевого слова ВЫБОР идёт одна или несколько веток КОГДА с условием, затем необязательная ветка ИНАЧЕ и завершающее слово КОНЕЦ. Условия проверяются последовательно, срабатывает первое истинное.
ВЫБОР
КОГДА Документы.Проведен
ТОГДА "Проведён"
КОГДА Документы.ПометкаУдаления
ТОГДА "Помечен на удаление"
ИНАЧЕ "Черновик"
КОНЕЦ КАК Состояние
Ветка ИНАЧЕ формально необязательна, но без неё при невыполнении всех условий поле получит значение NULL. Это частая причина «пустых» колонок в отчётах: разработчик забыл ИНАЧЕ, а часть строк не попала ни под одно условие. Рекомендуется всегда явно указывать ИНАЧЕ, хотя бы со значением NULL или пустой строкой — так поведение запроса становится предсказуемым.
Есть и краткая форма: ВЫБОР выражение КОГДА значение1 ТОГДА результат1 ... КОНЕЦ. В ней поле сравнивается на равенство с перечисленными значениями. Для ссылок краткая форма применима, но полная форма с логическими условиями используется чаще, потому что со ссылками обычно нужны проверки типа или соединения, а не простое равенство.
Проверка типа ссылки через ТИПЗНАЧЕНИЯ
Самый распространённый сценарий — поле составного типа, и нужно понять, на объект какого вида оно ссылается. Для этого служат функция ТИПЗНАЧЕНИЯ() и оператор ТИП(). Конструкция ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.РеализацияТоваровУслуг) возвращает истину, когда ссылка указывает именно на этот вид документа.
ВЫБОР
КОГДА ТИПЗНАЧЕНИЯ(Регистр.ДокументОснование) = ТИП(Документ.ПоступлениеТоваровУслуг)
ТОГДА "Поступление"
КОГДА ТИПЗНАЧЕНИЯ(Регистр.ДокументОснование) = ТИП(Документ.РеализацияТоваровУслуг)
ТОГДА "Реализация"
ИНАЧЕ "Прочее"
КОНЕЦ КАК ВидОснования
Такой приём позволяет обойтись без соединений с таблицами всех возможных документов: тип определяется по самой ссылке, что работает быстро и не раздувает запрос. Это стандартный способ «расшифровать» составные поля вроде оснований, владельцев, объектов расчётов в отчётах.
Сравнение ссылки с конкретным значением: ЗНАЧЕНИЕ и параметры
Когда нужно сравнить ссылку с конкретным элементом справочника или значением перечисления, есть два пути. Первый — функция ЗНАЧЕНИЕ(), которая обращается к предопределённому элементу или значению перечисления по имени: ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20). Второй — передача ссылки через параметр запроса оператором &ИмяПараметра.
ВЫБОР
КОГДА Товары.СтавкаНДС = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20)
ТОГДА Товары.Сумма * 20 / 120
КОГДА Товары.СтавкаНДС = ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС10)
ТОГДА Товары.Сумма * 10 / 110
ИНАЧЕ 0
КОНЕЦ КАК СуммаНДС
Ограничение ЗНАЧЕНИЕ() в том, что оно работает только с предопределёнными данными и перечислениями. Обычный (не предопределённый) элемент справочника так получить нельзя — его передают параметром. Параметр дополнительно даёт гибкость: один и тот же запрос можно выполнять с разными значениями без изменения текста.
ЗНАЧЕНИЕ или параметр
Подходит для перечислений и предопределённых элементов. Значение зашито в текст запроса, менять его из кода нельзя.
Подходит для любых ссылок, включая обычные элементы справочников и документы. Значение задаётся при выполнении, запрос универсальнее.
Через точку от ссылки можно тянуть реквизиты, но это порождает неявные соединения и замедляет запрос на больших таблицах.
Возврат ссылок разных типов и приведение через ВЫРАЗИТЬ
Главное ограничение ВЫБОР КОГДА со ссылками: все ветки ТОГДА и ИНАЧЕ должны возвращать значения совместимых типов. Если одна ветка возвращает ссылку на справочник «Контрагенты», а другая — на справочник «Организации», запрос выполнится, но тип поля станет составным. Проблемы начинаются, когда ветки возвращают принципиально несовместимые типы или когда платформа не может вывести тип поля — тогда запрос падает с ошибкой о несовместимости типов.
Решение — явное приведение функцией ВЫРАЗИТЬ(). Она ограничивает тип поля указанным типом, и все значения, не подходящие под него, превращаются в NULL. Это полезно и для составных полей: если из составного реквизита нужны только контрагенты, приведение отсекает остальное.
ВЫБОР
КОГДА ТИПЗНАЧЕНИЯ(Расчёты.Контрагент) = ТИП(Справочник.Контрагенты)
ТОГДА ВЫРАЗИТЬ(Расчёты.Контрагент КАК Справочник.Контрагенты)
ИНАЧЕ NULL
КОНЕЦ КАК Контрагент
Дополнительный эффект ВЫРАЗИТЬ — производительность. После приведения типа обращение к реквизитам поля через точку не требует проверки всех возможных типов, и платформа строит более простой план запроса. На больших таблицах разница заметна.
Практический сценарий: статус документа по ссылке на вид операции
Типовая задача из отчётов: вывести человекочитаемое состояние в зависимости от ссылочного реквизита. Например, классифицировать контрагентов по виду (юридическое или физическое лицо), где вид — ссылка на перечисление, хранящееся в реквизите справочника.
ВЫБРАТЬ
Контрагенты.Наименование,
ВЫБОР
КОГДА Контрагенты.ЮридическоеФизическоеЛицо = ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ЮридическоеЛицо)
ТОГДА "Юр. лицо"
КОГДА Контрагенты.ЮридическоеФизическоеЛицо = ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ФизическоеЛицо)
ТОГДА "Физ. лицо"
ИНАЧЕ "Не указано"
КОНЕЦ КАК ВидКонтрагента
ИЗ
Справочник.Контрагенты КАК Контрагенты
Обратите внимание на ветку ИНАЧЕ: она перехватывает не только незаполненные значения, но и ситуации, когда в базе появилось новое значение перечисления, не учтённое в запросе. Без ИНАЧЕ такие строки дали бы NULL, что в отчёте выглядело бы как ошибка данных.
- 1Определите тип поля: простая ссылка, составная ссылка или перечисление — от этого зависит способ сравнения.
- 2Для составного поля добавьте проверку ТИПЗНАЧЕНИЯ() или приведение ВЫРАЗИТЬ().
- 3Для конкретного значения используйте ЗНАЧЕНИЕ() (перечисления, предопределённые элементы) или параметр запроса.
- 4Добавьте ветку ИНАЧЕ с осмысленным значением по умолчанию.
- 5Выполните запрос в консоли и проверьте результат на строках с разными типами ссылок, включая пустые.
Типичные ошибки и как их исправить
Первая ошибка — сравнение ссылки со строкой. Записать КОГДА Поле = "Реализация" нельзя: ссылка никогда не равна строке, условие просто всегда ложно, и запрос молча возвращает значение из ИНАЧЕ. Правильно — сравнивать ссылку со ссылкой, а представление получать через функцию ПРЕДСТАВЛЕНИЕ() или реквизит Наименование.
Вторая ошибка — обращение к реквизиту составной ссылки без проверки типа. Если поле может ссылаться на разные документы, а вы пишете Поле.Номер, платформа построит соединения со всеми возможными таблицами. На больших базах это кратно замедляет запрос. Сначала сузьте тип через ВЫРАЗИТЬ или отберите нужные типы в условии ГДЕ.
Третья ошибка — NULL в сравнении. Пустая ссылка и NULL — разные вещи. Реквизит, которому не присвоено значение, содержит пустую ссылку соответствующего типа, а не NULL; NULL появляется после соединений, когда записи не нашлось. Поэтому проверку КОГДА Поле ЕСТЬ NULL и проверку на пустую ссылку нужно писать раздельно, если важны оба случая.
Проверка результата и отладка
Перед переносом запроса в код или СКД выполните его в консоли запросов на реальных данных и проверьте три вещи: тип результирующего поля, наличие NULL и поведение на граничных строках. Для проверки типа достаточно временно вывести само поле без ВЫБОР рядом с вычисляемой колонкой — так видно, какие ссылки попали в какую ветку.
Полезный приём отладки — заменить возвращаемые значения в ветках на номера условий (1, 2, 3). Тогда сразу видно, какое условие сработало для каждой строки, и легко найти строки, ушедшие в ИНАЧЕ. После отладки номера заменяются на боевые значения.
Как проверить результат
Один ожидаемый тип или осознанно составной
Составной тип там, где планировался один вид ссылки
Все строки заполнены осмысленными значениями
Часть строк содержит NULL без причины
Каждый тип попал в свою ветку
Все строки ушли в ИНАЧЕ — вероятно, ошибка в ТИП()
Обрабатываются отдельной веткой или ИНАЧЕ
Пустые ссылки смешаны с NULL после соединений
Альтернативы ВЫБОР КОГДА для работы со ссылками
Не всегда ВЫБОР КОГДА — оптимальный инструмент. Если соответствие «ссылка → значение» разрастается до десятков вариантов, лучше вынести его в таблицу значений, переданную в запрос как временную таблицу, и соединиться с ней. Такой запрос короче, быстрее и проще в сопровождении: соответствие меняется в коде, а не в тексте запроса.
Для отчётов на СКД часть логики можно перенести в вычисляемые поля или ресурсы, где доступен встроенный язык. Но переносить туда следует только оформительскую логику (форматирование, представления): фильтрация и соединения по ссылкам должны оставаться в запросе, иначе отчёт будет выбирать лишние данные и обрабатывать их в памяти.
Как выбрать подход
Что важно запомнить
ВЫБОР КОГДА со ссылками требует совместимости типов во всех ветках: используйте ТИПЗНАЧЕНИЯ() для проверки вида объекта, ЗНАЧЕНИЕ() для перечислений и предопределённых элементов, параметры для обычных ссылок и ВЫРАЗИТЬ() для приведения составных полей. Всегда добавляйте ИНАЧЕ и различайте NULL и пустую ссылку.
Частые вопросы
Можно ли в ВЫБОР КОГДА вернуть саму ссылку, а не строку?
Да, ветки ТОГДА могут возвращать ссылочные значения — например, подставить другого контрагента в зависимости от условия. Главное, чтобы все ветки возвращали совместимые типы; при необходимости используйте ВЫРАЗИТЬ() для приведения к нужному типу ссылки.
Почему запрос с ВЫБОР КОГДА возвращает NULL, хотя данные есть?
Чаще всего ни одно условие не выполнилось, а ветка ИНАЧЕ отсутствует. Другая причина — сравнение ссылки со строкой или с неправильным типом: такое условие всегда ложно. Проверьте, что сравниваются ссылка со ссылкой, и добавьте ИНАЧЕ.
Как в условии проверить, что ссылка пустая?
Сравните поле с пустой ссылкой через ЗНАЧЕНИЕ(): например, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка). Учтите, что после левого соединения отсутствующее значение — это NULL, а не пустая ссылка, поэтому нужна отдельная проверка ЕСТЬ NULL.
Чем ТИПЗНАЧЕНИЯ отличается от ВЫРАЗИТЬ?
ТИПЗНАЧЕНИЯ() только возвращает тип значения для сравнения — это проверка. ВЫРАЗИТЬ() изменяет (ограничивает) тип самого поля: значения неподходящего типа превращаются в NULL. Обычно их комбинируют: сначала проверяют тип, затем приводят поле для безопасного обращения к реквизитам.
Работает ли ВЫБОР КОГДА в динамических списках и СКД?
Да, конструкция поддерживается везде, где используется язык запросов: в динамических списках, схемах компоновки данных, виртуальных таблицах. В СКД дополнительно доступны вычисляемые поля на встроенном языке, но базовую логику со ссылками лучше оставлять в запросе.
Влияет ли количество веток КОГДА на скорость запроса?
Умеренное число веток практически не влияет на производительность — условия вычисляются построчно. Замедление возникает, если внутри условий есть обращения к реквизитам составных ссылок без приведения типа или вложенные запросы. При десятках вариантов соответствия эффективнее соединение с временной таблицей.