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

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

Как в запросе 1С проверить тип ссылки

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

Проверка типа ссылки — одна из самых частых задач при работе с составными полями в запросах 1С. Поле «Основание», «Документ-основание», «Контрагент» в расширенных конфигурациях часто может хранить ссылки на разные виды документов или справочников, и без проверки типа невозможно корректно соединить таблицы или отфильтровать данные.

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

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

Что такое составной тип и зачем проверять тип ссылки

Составной тип данных — это свойство реквизита, которое разрешает хранить ссылки на объекты разных видов. Например, реквизит «Контрагент» в регистре взаиморасчётов может быть типа «СправочникСсылка.Контрагенты» и одновременно «СправочникСсылка.Организации». Пока вы просто выводите это поле в результат запроса, проблем нет — платформа сама вернёт нужную ссылку.

Сложности начинаются, когда нужно обратиться к реквизиту такой ссылки. Запрос вида ВЫБРАТЬ Т.Контрагент.ИНН для составного поля вернёт NULL для всех строк, где ссылка указывает не на тот вид справочника, у которого есть реквизит «ИНН». Платформа не может заранее знать, какой именно объект окажется в поле, поэтому «точечная» навигация по составному типу без приведения работает непредсказуемо.

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

Способ 1: функция ТИПЗНАЧЕНИЯ() в сочетании с ТИП()

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

ВЫБРАТЬ

Регистр.Основание КАК Основание,

ВЫБОР

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

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

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

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

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

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

ИЗ

РегистрНакопления.Взаиморасчеты КАК Регистр

ГДЕ

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

Обратите внимание на синтаксис аргумента ТИП(): указывается имя вида объекта и через точку имя конкретного объекта метаданных — без кавычек, не строкой. Написание ТИП("Документ.РеализацияТоваровУслуг") вызовет ошибку построения запроса, потому что функция ожидает именно литерал типа, а не строку.

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

Способ 2: оператор ССЫЛКА

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

ВЫБРАТЬ

Заказы.Контрагент КАК Контрагент,

Заказы.Сумма КАК Сумма

ИЗ

Документ.ЗаказПокупателя КАК Заказы

ГДЕ

Заказы.Контрагент ССЫЛКА Справочник.Контрагенты

И НЕ Заказы.ПометкаУдаления

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

Важно понимать: ССЫЛКА проверяет вид объекта, а не конкретную ссылку. Условие Поле ССЫЛКА Документ.РеализацияТоваровУслуг пропустит все документы этого вида. Если нужно сравнить с конкретным документом, используйте обычное равенство с параметром: Поле = &Документ.

ТИПЗНАЧЕНИЯ или ССЫЛКА

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

Подходит для ветвлений ВЫБОР, группировок по видам объектов и сложной логики. Длиннее запись.

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

Короткая и читаемая проверка в условиях ГДЕ и соединениях. Менее удобна для многоуровневых ветвлений.

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

Не проверка, а приведение типа. Используется для доступа к реквизитам и ускорения соединений.

Способ 3: ВЫРАЗИТЬ — приведение типа для доступа к реквизитам

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

ВЫБРАТЬ

ВЫРАЗИТЬ(Регистр.Контрагент КАК Справочник.Контрагенты).ИНН КАК ИНН,

ВЫРАЗИТЬ(Регистр.Контрагент КАК Справочник.Контрагенты).КПП КАК КПП

ИЗ

РегистрНакопления.Взаиморасчеты КАК Регистр

Для строк, где «Контрагент» — действительно ссылка на справочник «Контрагенты», поля ИНН и КПП заполнятся. Для остальных строк вернётся NULL, что само по себе является косвенной проверкой типа: ВЫРАЗИТЬ(...) ЕСТЬ НЕ NULL означает, что тип совпал. Однако прямое сравнение через ССЫЛКА читается лучше, поэтому ВЫРАЗИТЬ применяйте именно для доступа к реквизитам, а не как замену проверки.

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

ВЫБРАТЬ

Заказы.Номер КАК Номер,

Контрагенты.Наименование КАК Контрагент

ИЗ

Документ.ЗаказПокупателя КАК Заказы

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты

ПО Заказы.Контрагент = Контрагенты.Ссылка

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

Проверка типа в параметрах виртуальных таблиц и СКД

Когда отбор по типу нужен в отчёте на СКД или в запросе к виртуальной таблице регистра, эффективнее передавать условие в параметры виртуальной таблицы, а не фильтровать результат после выборки. Например, для регистра сведений с составным измерением условие с ССЫЛКА можно указать прямо в параметре «Условие» виртуальной таблицы — тогда СУБД отфильтрует записи до соединений и агрегации.

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

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

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

Типичные ошибки и как их избежать

Самая распространённая ошибка — ожидание, что «точечное» обращение к реквизиту составного поля автоматически отфильтрует записи нужного вида. На деле запрос ВЫБРАТЬ Т.Поле.ИНН вернёт все строки, просто с NULL там, где тип не подошёл. Если нужна фильтрация — добавляйте явное условие ГДЕ Т.Поле ССЫЛКА Справочник.Контрагенты.

Вторая ошибка — передача строки в ТИП(). Запись ТИП("Справочник.Номенклатура") синтаксически недопустима: аргумент должен быть литералом типа без кавычек. Если вид объекта должен определяться динамически (например, из параметра), в языке запросов это невозможно напрямую — придётся формировать текст запроса программно или перечислять варианты через ВЫБОР.

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

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

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

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

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

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

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

Колонка ТИПЗНАЧЕНИЯ(Поле) в выборке
Норма

Отображаются ожидаемые виды объектов

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

Присутствуют неожиданные типы, не учтённые в логике запроса

Совпадение счётчиков
Норма

Количество строк с условием ССЫЛКА равно количеству строк, где ВЫРАЗИТЬ дал не NULL

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

Числа расходятся — вероятны битые ссылки или ошибка в условии

Время выполнения запроса
Норма

Запрос с ВЫРАЗИТЬ в соединении выполняется за приемлемое время на рабочей базе

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

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

FAQ

Можно ли проверить тип ссылки, если вид объекта хранится в параметре?

Напрямую нет: функция ТИП() принимает только литерал типа, а не параметр. Обходные пути — сформировать текст запроса программно, подставив нужный вид объекта, или перечислить все допустимые варианты через ВЫБОР и сравнивать с параметром-строкой ветвление за пределами запроса.

Чем отличается проверка ССЫЛКА от сравнения с конкретным документом?

Оператор ССЫЛКА проверяет вид объекта: условие «Поле ССЫЛКА Документ.РеализацияТоваровУслуг» пропускает все документы этого вида. Сравнение «Поле = &Ссылка» отбирает ровно один конкретный документ. Это разные задачи: фильтрация по виду против поиска по значению.

Почему ВЫРАЗИТЬ возвращает NULL, хотя ссылка заполнена?

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

Работает ли ТИПЗНАЧЕНИЯ с примитивными типами — строкой, числом, датой?

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

Как проверить тип в расширении запроса динамического списка, не меняя основной запрос?

Добавьте в произвольный запрос динамического списка вычисляемую колонку вида «ВЫБОР КОГДА Поле ССЫЛКА Документ.ПриходныйОрдер ТОГДА ...» и включите её в доступные поля. Пользователи смогут строить отборы по этой колонке стандартными средствами без изменения основного текста запроса.

Влияет ли проверка типа на скорость запроса?

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

Итог

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

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