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