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

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

Сравнение типов в запросе 1С: ТИПЗНАЧЕНИЯ, ССЫЛКА и приведение типов

Как сравнить тип значения в запросе 1С: функции ТИПЗНАЧЕНИЯ, ССЫЛКА, ТИП, ВЫРАЗИТЬ. Примеры, приведение типов, ошибки и проверка результата.

В языке запросов 1С нет оператора «сравнить тип» в привычном виде, но задача решается тремя штатными средствами: функцией ТИПЗНАЧЕНИЯ, литералом ТИП(...) и выражением ССЫЛКА. Все три входят в стандарт языка запросов и работают на любой поддерживаемой платформе 8.3 без дополнительных расширений.

Чаще всего сравнение типов нужно при работе с полями составного типа: документ «Реализация товаров» может быть основанием для разных документов, реквизит «Контрагент» в некоторых конфигурациях хранит и справочник, и строку, а регистры сведений с измерением произвольного типа встречаются в типовых решениях повсеместно. Без проверки типа такие запросы либо возвращают лишние строки, либо падают с ошибкой соединения таблиц.

Вторая типичная ситуация — отбор по конкретному виду документа или справочника через параметр. Если в запрос передаётся ссылка, платформа сама знает её тип, но если нужно отобрать «все документы вида ПоступлениеТоваров» из составного реквизита, без явного сравнения типов не обойтись.

Функция ТИПЗНАЧЕНИЯ и литерал ТИП: точное сравнение типов

Основной способ — функция ТИПЗНАЧЕНИЯ(Поле), которая возвращает тип значения поля, и литерал ТИП(ИмяТипа), задающий тип для сравнения. Сравнение выполняется обычным знаком равенства в секции ГДЕ:

bsl
ВЫБРАТЬ
	Свойства.Объект КАК Объект
ИЗ
	РегистрСведений.ДополнительныеСведения КАК Свойства
ГДЕ
	ТИПЗНАЧЕНИЯ(Свойства.Объект) = ТИП(Справочник.Номенклатура)

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

Важное ограничение: ТИПЗНАЧЕНИЯ возвращает фактический тип хранящегося значения, а не тип реквизита. Если поле составного типа и в конкретной строке лежит ссылка на справочник «Номенклатура», сравнение сработает, даже если реквизит объявлен как «документ или справочник». Если значение — NULL (например, при левом соединении), функция вернёт NULL, и условие не выполнится: NULL = ТИП(...) всегда даёт неопределённость, а не «истина».

Условие ССЫЛКА: компактная альтернатива

Для ссылочных типов есть более короткий синтаксис — оператор ССЫЛКА. Он проверяет, что значение является ссылкой на указанный вид объекта:

bsl
ВЫБРАТЬ
	Заказы.ДокументОснование КАК Основание
ИЗ
	Документ.ЗаказПокупателя КАК Заказы
ГДЕ
	Заказы.ДокументОснование ССЫЛКА Документ.СчетНаОплатуПокупателю

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

Оба варианта применимы в секциях ГДЕ, ИМЕЮЩИЕ, в условиях соединения и в операторе ВЫБОР. Для виртуальных таблиц проверку типа лучше выносить в параметры виртуальной таблицы, если она поддерживает отбор: фильтрация на уровне СУБД до выборки данных быстрее, чем постобработка.

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

ТИПЗНАЧЕНИЯ(Поле) = ТИП(...)

Универсально: ссылки, числа, строки, даты. Чуть многословнее, работает везде.

Поле ССЫЛКА ВидОбъекта

Короче и нагляднее, но только для ссылочных типов. Не подходит для примитивов.

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

Не сравнение, а приведение: несовпадающие значения превращаются в NULL. Используется для соединений и вложенных полей.

Приведение типов через ВЫРАЗИТЬ

Когда нужно не просто отфильтровать, а обратиться к реквизитам объекта через точку, применяют оператор ВЫРАЗИТЬ. Он приводит значение составного поля к заданному типу; если тип не совпадает, результат — NULL:

bsl
ВЫБРАТЬ
	Свойства.Объект КАК Объект,
	ВЫРАЗИТЬ(Свойства.Объект КАК Справочник.Номенклатура).Артикул КАК Артикул
ИЗ
	РегистрСведений.ДополнительныеСведения КАК Свойства
ГДЕ
	Свойства.Объект ССЫЛКА Справочник.Номенклатура

Здесь условие ССЫЛКА гарантирует, что приведение сработает, а обращение к реквизиту Артикул не вызовет ошибку. Без ВЫРАЗИТЬ платформа при обращении через точку к полю составного типа неявно строит соединения со всеми таблицами возможных типов — это резко увеличивает стоимость запроса и является одной из главных причин медленных запросов по составным полям.

Признак корректной работы: в результате запроса колонка с приведённым реквизитом заполнена только для строк нужного типа, остальные строки содержат NULL. Если NULL появился там, где ожидалось значение, — значит, тип фактических данных не совпал с типом в ВЫРАЗИТЬ.

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

Иногда тип нужно сравнить не с жёстко заданным литералом, а с типом переданного параметра. Прямого способа получить «тип параметра» в языке запросов нет, поэтому используют обходной приём: сравнивают ТИПЗНАЧЕНИЯ(Поле) с ТИПЗНАЧЕНИЯ(&Параметр):

bsl
ГДЕ
	ТИПЗНАЧЕНИЯ(Свойства.Объект) = ТИПЗНАЧЕНИЯ(&Образец)

Параметр &Образец должен содержать ссылку нужного вида — например, пустую ссылку Справочники.Номенклатура.ПустаяСсылка(), полученную в коде модуля. Это удобно, когда вид объекта выбирает пользователь, и запрос строится универсально.

Альтернатива — передавать в параметр строку с именем типа и строить текст запроса динамически через подстановку ТИП(Справочник." + ИмяТипа + "). Такой подход гибче, но требует контроля допустимых значений: подставлять в текст запроса произвольный ввод пользователя нельзя, это источник ошибок и потенциальных проблем с безопасностью.

Типовые сценарии: отбор, группировка, ВЫБОР

Отбор документов конкретного вида из составного реквизита

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

Разная логика для разных типов через ВЫБОР

Оператор ВЫБОР позволяет вернуть разные поля в зависимости от типа значения — например, для номенклатуры показать артикул, а для контрагента ИНН:

bsl
ВЫБРАТЬ
	ВЫБОР
		КОГДА Т.Объект ССЫЛКА Справочник.Номенклатура
			ТОГДА ВЫРАЗИТЬ(Т.Объект КАК Справочник.Номенклатура).Артикул
		КОГДА Т.Объект ССЫЛКА Справочник.Контрагенты
			ТОГДА ВЫРАЗИТЬ(Т.Объект КАК Справочник.Контрагенты).ИНН
		ИНАЧЕ ""
	КОНЕЦ КАК Реквизит
ИЗ
	РегистрСведений.ДополнительныеСведения КАК Т

Проверка примитивных типов

Для полей, способных хранить строки и числа одновременно (например, значения свойств), сравнение выглядит так: ТИПЗНАЧЕНИЯ(Значение) = ТИП(СТРОКА). Это позволяет отделить числовые значения от текстовых перед агрегацией — попытка просуммировать строки приведёт к ошибке исполнения запроса.

Порядок действий при работе с составным полем
  1. 1
    Определите, какие типы реально хранятся в поле: выполните запрос с ТИПЗНАЧЕНИЯ(Поле) и группировкой.
  2. 2
    Добавьте отбор по нужному типу через ССЫЛКА или ТИПЗНАЧЕНИЯ = ТИП(...).
  3. 3
    Приведите поле через ВЫРАЗИТЬ к нужному типу перед обращением к реквизитам через точку.
  4. 4
    Проверьте результат на тестовых данных: количество строк, отсутствие неожиданных NULL.
  5. 5
    Оцените время выполнения на рабочем объёме данных, при необходимости перенесите отбор в параметры виртуальной таблицы.

Частые ошибки и ограничения

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

Вторая — забытый NULL. При левом соединении или в необязательных реквизитах поле может быть пустым, и условие по типу молча отбросит такие строки. Если строки должны остаться в выборке, добавляйте ИЛИ Поле ЕСТЬ NULL.

Третья — обращение через точку к полю составного типа без приведения. Кроме падения производительности, в некоторых случаях запрос завершится ошибкой, если состав типов включает несовместимые для соединения варианты. Четвёртая — попытка использовать ССЫЛКА с примитивным типом: синтаксис этого не допускает, применяйте ТИПЗНАЧЕНИЯ.

Типичные ошибки
01
Сравнение ТИПЗНАЧЕНИЯ со строкой в кавычках — условие никогда не выполнится или запрос не скомпилируется.
02
Игнорирование NULL: строки с пустым полем теряются из выборки без предупреждения.
03
Обращение к реквизитам составного поля без ВЫРАЗИТЬ — неявные соединения со всеми таблицами и резкое замедление запроса.
04
Использование ССЫЛКА для примитивных типов — синтаксическая ошибка; для строк и чисел нужен ТИПЗНАЧЕНИЯ.
05
Подстановка пользовательского ввода в текст запроса без проверки — риск ошибок и небезопасного кода.

Как проверить результат и что учесть по производительности

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

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

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

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

Состав типов в поле
Норма

Запрос с группировкой по ТИПЗНАЧЕНИЯ показывает ожидаемые виды объектов

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

Появились неожиданные типы или NULL — условия запроса не покрывают реальные данные

Заполнение приведённых реквизитов
Норма

Колонка после ВЫРАЗИТЬ заполнена для строк нужного типа

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

NULL там, где ожидались значения — тип в ВЫРАЗИТЬ не совпадает с фактическим

Скорость выполнения
Норма

Запрос по составному полю с отбором по типу выполняется за приемлемое время

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

Минуты выполнения — вероятно, есть обращения через точку без приведения или полное сканирование большой таблицы

Итог

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

Точное сравнение типа — ТИПЗНАЧЕНИЯ(Поле) = ТИП(Вид.Имя), для ссылок короче условие ССЫЛКА. Перед обращением к реквизитам составного поля приводите его через ВЫРАЗИТЬ. Помните про NULL и не подставляйте непроверенный ввод в текст запроса.

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

Можно ли сравнить тип значения в запросе без жёсткого указания вида объекта?

Да, через сравнение ТИПЗНАЧЕНИЯ(Поле) = ТИПЗНАЧЕНИЯ(&Параметр), где параметр — любая ссылка нужного вида, например пустая ссылка, полученная в коде. Запрос при этом остаётся универсальным и не требует переписывания текста.

Чем отличается ССЫЛКА от ТИПЗНАЧЕНИЯ?

Функционально для ссылочных типов они эквивалентны: оба проверяют вид объекта. Разница в области применения — ССЫЛКА работает только со ссылками и записывается короче, а ТИПЗНАЧЕНИЯ дополнительно поддерживает примитивные типы: число, строку, дату, булево.

Почему условие по типу отбрасывает часть строк, хотя поле заполнено?

Скорее всего, в поле хранится NULL — например, из-за левого соединения или незаполненного реквизита. ТИПЗНАЧЕНИЯ(NULL) даёт NULL, и сравнение не выполняется. Добавьте в условие «ИЛИ Поле ЕСТЬ NULL», если такие строки должны попадать в выборку.

Как обратиться к реквизиту документа, если поле составного типа?

Сначала отфильтруйте строки по типу через ССЫЛКА или ТИПЗНАЧЕНИЯ, затем приведите поле оператором ВЫРАЗИТЬ(Поле КАК Документ.НужныйВид) и только после этого обращайтесь к реквизиту через точку. Это и безопаснее, и значительно быстрее.

Можно ли использовать сравнение типов в секции ИМЕЮЩИЕ или в условии соединения?

Да, ТИПЗНАЧЕНИЯ и ССЫЛКА допустимы в секциях ГДЕ, ИМЕЮЩИЕ, в условиях соединений и в операторе ВЫБОР. Ограничение одно: для виртуальных таблиц эффективнее передавать отбор в параметры самой таблицы, если она его поддерживает.

Медленно работает запрос с проверкой типа по большой таблице. Что делать?

Индексов по типу значения нет, поэтому отбор идёт полным сканированием. Варианты: хранить вид объекта в отдельном индексированном реквизите, сокращать выборку другими индексированными условиями до проверки типа, либо перенести фильтрацию в параметры виртуальной таблицы.