К статье
Практический материал

Разработка и Конфигурация · 12 мин

1С: ВЫБОР КОГДА и ТИПЗНАЧЕНИЯ — как проверять типы полей в запросах

Как использовать конструкцию ВЫБОР КОГДА вместе с функцией ТИПЗНАЧЕНИЯ в запросах 1С: синтаксис, примеры проверки типов полей, типичные ошибки и альтернативы.

Конструкция ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ в языке запросов 1С — аналог оператора CASE в SQL. Она позволяет возвращать разные значения в зависимости от условий, не прибегая к постобработке результата в коде. Одна из самых частых практических задач — определить, значение какого типа хранится в поле составного типа, и по-разному обработать, например, контрагента-организацию и контрагента-физлицо.

Для проверки типа внутри ВЫБОР КОГДА используется функция ТИПЗНАЧЕНИЯ(Поле) в сочетании с литералом ТИП(ИмяТипа). Связка выглядит так: ВЫБОР КОГДА ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.РеализацияТоваровУслуг) ТОГДА "Реализация" ... КОНЕЦ. Такой приём незаменим при работе с регистраторами регистров, полями составного типа и планами обмена.

Ошибки в этой конструкции встречаются регулярно: разработчики путают порядок аргументов, забывают ветку ИНАЧЕ, сравнивают типы через приведение к строке или пытаются проверить тип у поля, которое уже имеет единственный тип. Ниже разобраны синтаксис, рабочие примеры, ограничения и способы проверить результат.

Синтаксис ВЫБОР КОГДА и где уместна проверка типа

Общий вид конструкции: ВЫБОР КОГДА Условие1 ТОГДА Значение1 КОГДА Условие2 ТОГДА Значение2 ИНАЧЕ ЗначениеПоУмолчанию КОНЕЦ. Условий КОГДА может быть сколько угодно, они вычисляются сверху вниз, и срабатывает первое истинное. Если ни одно условие не выполнилось и ветки ИНАЧЕ нет, результатом будет NULL — это частый источник скрытых ошибок в отчётах.

Проверка типа нужна там, где поле имеет составной тип: регистратор регистра накопления или сведений, реквизит с типом «ДокументСсылка.НесколькоВидов», поле «Объект» в задачах, определяемые типы в конфигурациях на БСП. Во всех этих случаях одно и то же поле в разных строках содержит ссылки разных метаданных, и логика должна реагировать на это по-разному.

Простейший пример — подписать строки таблицы значений в зависимости от типа регистратора:

ВЫБРАТЬ

Движения.Регистратор КАК Регистратор,

ВЫБОР

КОГДА ТИПЗНАЧЕНИЯ(Движения.Регистратор) = ТИП(Документ.РеализацияТоваровУслуг)

ТОГДА "Продажа"

КОГДА ТИПЗНАЧЕНИЯ(Движения.Регистратор) = ТИП(Документ.ПоступлениеТоваровУслуг)

ТОГДА "Закупка"

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

КОНЕЦ КАК ВидОперации

ИЗ

РегистрНакопления.ТоварыНаСкладах КАК Движения

Как работает ТИПЗНАЧЕНИЯ и литерал ТИП

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

ТИП(ИмяТипа) — литерал типа. Внутри скобок указывается полное имя объекта метаданных: ТИП(Документ.РеализацияТоваровУслуг), ТИП(Справочник.Контрагенты), ТИП(Перечисление.ВидыОпераций). Для примитивных типов синтаксис другой: ТИП(ЧИСЛО), ТИП(СТРОКА), ТИП(ДАТА), ТИП(БУЛЕВО) — без точки и имени.

Важное следствие: сравнение типов — строгое. Если поле содержит ссылку на документ «РеализацияТоваровУслуг», то сравнение с ТИП(Документ.ПоступлениеТоваровУслуг) вернёт ложь, даже если оба документа делают похожие движения. Наследования типов в языке запросов 1С нет.

Практические сценарии использования

Разная обработка строк по типу регистратора

Классическая задача — отчёт по регистру, где сумму нужно брать с разным знаком в зависимости от документа-источника. Например, приходные ордера считаются в плюс, расходные — в минус:

ВЫБРАТЬ

СУММА(ВЫБОР

КОГДА ТИПЗНАЧЕНИЯ(Движения.Регистратор) = ТИП(Документ.ПриходныйОрдерНаТовары)

ТОГДА Движения.Количество

КОГДА ТИПЗНАЧЕНИЯ(Движения.Регистратор) = ТИП(Документ.РасходныйОрдерНаТовары)

ТОГДА -Движения.Количество

ИНАЧЕ 0

КОНЕЦ) КАК Остаток

ИЗ

РегистрНакопления.ТоварыВСкладскихЯчейках КАК Движения

Получение реквизита через точку только для нужного типа

Если обратиться к реквизиту через точку от поля составного типа, для строк с «чужим» типом вернётся NULL. Это можно использовать намеренно: ВЫРАЗИТЬ(Поле КАК Документ.РеализацияТоваровУслуг).Организация даст организацию только там, где ссылка именно на реализацию. Однако сравнение через ТИПЗНАЧЕНИЯ читается явнее и безопаснее при рефакторинге.

Проверка примитивных типов в полях составного типа

Реквизиты вроде «Значение» в регистрах сведений или свойствах могут хранить и строку, и число, и ссылку. Разделить их в отчёте помогает та же связка: ВЫБОР КОГДА ТИПЗНАЧЕНИЯ(Свойство.Значение) = ТИП(СТРОКА) ТОГДА "Текст" КОГДА ТИПЗНАЧЕНИЯ(Свойство.Значение) = ТИП(ЧИСЛО) ТОГДА "Число" ИНАЧЕ "Ссылка" КОНЕЦ.

Порядок действий при добавлении проверки типа
  1. 1
    Определите поле составного типа, которое нужно анализировать (например, Регистратор или реквизит с типом ОпределяемыйТип).
  2. 2
    Выпишите все типы, которые поле может принимать по метаданным: смотрите состав типа в конфигураторе.
  3. 3
    Напишите ВЫБОР КОГДА с отдельной веткой ТИПЗНАЧЕНИЯ(Поле) = ТИП(...) для каждого значимого типа.
  4. 4
    Добавьте ветку ИНАЧЕ с безопасным значением по умолчанию (0, пустая строка или явная пометка).
  5. 5
    Выполните запрос в консоли запросов и проверьте, что для каждого реального типа срабатывает своя ветка, а ИНАЧЕ не маскирует пропущенные типы.

ВЫБОР КОГДА против ВЫРАЗИТЬ и ССЫЛКА: что выбрать

Проверка типа — не единственный способ ограничить составное поле. Оператор ВЫРАЗИТЬ(Поле КАК Тип) приводит значение к указанному типу, а условие Поле ССЫЛКА Документ.РеализацияТоваровУслуг фильтрует записи, где ссылка именно этого вида. У каждого приёма своя область применения.

Сравнение способов работы с составными типами

ВЫБОР КОГДА + ТИПЗНАЧЕНИЯ

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

Условие ССЫЛКА

Подходит для фильтрации в ГДЕ: Поле ССЫЛКА Документ.РеализацияТоваровУслуг. Убирает строки с другими типами, но не позволяет вернуть альтернативное значение.

ВЫРАЗИТЬ(Поле КАК Тип)

Подходит для сужения типа перед обращением к реквизитам через точку или перед соединением. Для несовпадающих типов даёт NULL без возможности задать замену внутри самого выражения.

На практике приёмы комбинируют: сначала ветвление через ВЫБОР КОГДА ТИПЗНАЧЕНИЯ для логики, затем ВЫРАЗИТЬ внутри ветки, чтобы добраться до реквизита конкретного документа. Например, для реализации вытащить склад, а для перемещения — склад-отправитель.

Типичные ошибки и ограничения

Первая группа ошибок — синтаксические: пропущенное КОНЕЦ, ТОГДА вместо ТОГДА после ИНАЧЕ (после ИНАЧЕ значение пишется без условия), опечатка в имени метаданных внутри ТИП(...). Запрос с такой ошибкой просто не выполнится, и конструктор запроса подсветит проблемное место.

Вторая группа — логические. Самая коварная: разработчик перечисляет в КОГДА только те типы, которые встретились в тестовой базе, а ветку ИНАЧЕ заполняет нулём. В рабочей базе появляется документ нового вида, и его движения молча обнуляются в отчёте. Безопаснее в ИНАЧЕ возвращать явную пометку вроде строки «Не учтён» — так пропуск быстро заметят.

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

Типичные ошибки
01
Отсутствие ветки ИНАЧЕ: для неперечисленных типов результат становится NULL, что ломает группировки и итоги.
02
Сравнение типа через ПОДСТРОКА или строковое представление ссылки — хрупко и зависит от формата представления.
03
Попытка вывести ТИПЗНАЧЕНИЯ(Поле) как поле результата и ожидать читаемое имя типа — функция предназначена только для сравнения.
04
Проверка типа у поля, у которого в метаданных единственный тип: условие всегда истинно или всегда ложно, код бессмысленен.
05
Имя метаданных в ТИП(...) указано без вида объекта: ТИП(РеализацияТоваровУслуг) вместо ТИП(Документ.РеализацияТоваровУслуг) — запрос не выполнится.

Как проверить, что конструкция работает правильно

Надёжный способ — временно вывести в результат запроса само поле типа и вычисляемую колонку рядом, затем проконтролировать соответствие в консоли запросов. Для каждого реального значения типа в выборке должна срабатывать своя ветка, а значение из ИНАЧЕ — появляться только там, где это ожидаемо.

Дополнительный приём — сверка количества строк: сгруппируйте запрос по вычисляемой колонке и сравните с группировкой по ТИПЗНАЧЕНИЯ в отдельном тестовом запросе. Если суммы по группам расходятся, значит, какой-то тип попал не в ту ветку.

Контрольные точки

Как проверить результат

Колонка с ВЫБОР КОГДА для каждого типа регистратора
Норма

Каждому типу соответствует своё значение, ИНАЧЕ почти не встречается

Тревожный признак

Большинство строк упало в ИНАЧЕ — вероятно, опечатка в имени типа

Итоги по группировке вычисляемой колонки
Норма

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

Тревожный признак

Итоги меньше — часть строк обнулилась в неверной ветке

Поля с NULL в результате
Норма

NULL только там, где это осознанное решение

Тревожный признак

NULL в строках с заполненным регистратором — забыта ветка ИНАЧЕ или пропущен тип

Альтернативы и смежные приёмы

Если ветвление нужно только для представления, а не для расчётов, иногда проще вернуть ссылку как есть и обработать тип уже в коде встроенного языка через ТипЗнч(Значение) и Тип("ДокументСсылка.РеализацияТоваровУслуг"). Это оправдано, когда логика сложная и в запросе превращается в простыню из десятка КОГДА.

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

Итог

Что важно запомнить

Проверка типа в запросе 1С делается связкой ВЫБОР КОГДА ТИПЗНАЧЕНИЯ(Поле) = ТИП(Вид.Имя) ТОГДА ... ИНАЧЕ ... КОНЕЦ. Всегда добавляйте ИНАЧЕ с явным значением, перечисляйте все типы из состава поля в метаданных и проверяйте результат группировкой по вычисляемой колонке. Для фильтрации строк используйте ССЫЛКА, для сужения типа — ВЫРАЗИТЬ.

Частые вопросы

Можно ли вывести название типа поля строкой в результате запроса?

Напрямую — нет, функция ТИПЗНАЧЕНИЯ возвращает значение типа «Тип», которое не имеет строкового представления в запросе. Обходной путь — конструкция ВЫБОР КОГДА, где для каждого типа вручную возвращается его название строкой.

Чем ТИПЗНАЧЕНИЯ отличается от ТипЗнч()?

ТИПЗНАЧЕНИЯ — функция языка запросов, работает только внутри текста запроса. ТипЗнч() — функция встроенного языка, применяется к переменным в коде модуля. Логика одна, но контексты использования разные, и подставить одну вместо другой нельзя.

Что вернёт ВЫБОР КОГДА, если ни одно условие не сработало?

Если ветка ИНАЧЕ задана — её значение. Если ИНАЧЕ нет — NULL. Такой NULL потом влияет на группировки, соединения и агрегатные функции, поэтому ветку ИНАЧЕ рекомендуется писать всегда.

Можно ли проверить примитивный тип, например что поле содержит число?

Да. Для примитивов в литерале ТИП указывается ключевое слово без вида объекта: ТИП(ЧИСЛО), ТИП(СТРОКА), ТИП(ДАТА), ТИП(БУЛЕВО). Сравнение выглядит так: ТИПЗНАЧЕНИЯ(Поле) = ТИП(ЧИСЛО).

Влияет ли ВЫБОР КОГДА с ТИПЗНАЧЕНИЯ на производительность запроса?

Само сравнение типов недорогое. Замедление обычно вызывают обращения через точку к реквизитам составного поля внутри веток — платформа строит соединения с таблицами всех возможных типов. На больших таблицах такие запросы стоит проверять на реальных данных и при необходимости разбивать на несколько с последующим объединением.

Как отфильтровать записи только с нужным типом регистратора?

Для фильтрации удобнее оператор ССЫЛКА в секции ГДЕ: ГДЕ Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг. ВЫБОР КОГДА для фильтрации не нужен — он предназначен для ветвления возвращаемых значений.