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

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

Как сравнить тип значения в запросе 1С

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

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

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

Неправильное сравнение типов — частая причина ошибок «Несовместимые типы» и пустых выборок там, где данные на самом деле есть. Ниже разобраны все рабочие способы с примерами кода, ограничениями и типичными ошибками.

Какие инструменты даёт язык запросов для работы с типами

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

Второй механизм — оператор ССЫЛКА. Конструкция «Поле ССЫЛКА Справочник.Номенклатура» возвращает Истина, если значение является ссылкой на указанный тип объекта. Это более короткий и читаемый способ проверки для ссылочных типов.

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

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

ТИПЗНАЧЕНИЯ + ТИП

Универсальный способ: работает и для ссылок, и для примитивных типов (Число, Строка, Дата). Чуть многословнее.

Оператор ССЫЛКА

Короткая проверка только для ссылочных типов. Не подходит для Число, Строка, Булево, Дата.

ВЫРАЗИТЬ

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

Сравнение через ТИПЗНАЧЕНИЯ и литерал ТИП

Функция ТИПЗНАЧЕНИЯ применяется к полю или выражению и возвращает его тип. Сравнение выполняется обычным оператором равенства с литералом ТИП:

ВЫБРАТЬ

Платеж.Плательщик КАК Плательщик

ИЗ

Документ.ПлатежноеПоручение КАК Платеж

ГДЕ

ТИПЗНАЧЕНИЯ(Платеж.Плательщик) = ТИП(Справочник.Контрагенты)

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

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

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

Проверка ссылочного типа оператором ССЫЛКА

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

ВЫБРАТЬ

Состав.Значение КАК Значение

ИЗ

РегистрСведений.ДополнительныеСведения КАК Состав

ГДЕ

Состав.Значение ССЫЛКА Справочник.Номенклатура

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

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

Выбор действия по типу значения через ВЫБОР и КОГДА

На практике сравнение типа редко нужно само по себе — обычно требуется по-разному обработать значения разных типов. Для этого сравнение типа помещают в конструкцию ВЫБОР:

ВЫБРАТЬ

ВЫБОР

КОГДА ТИПЗНАЧЕНИЯ(Расчёты.Контрагент) = ТИП(Справочник.Контрагенты)

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

КОГДА Расчёты.Контрагент ССЫЛКА Справочник.Сотрудники

ТОГДА ВЫРАЗИТЬ(Расчёты.Контрагент КАК Справочник.Сотрудники).Наименование

ИНАЧЕ "Не задано"

КОНЕЦ КАК НаименованиеКонтрагента

ИЗ

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

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

Ветки ВЫБОР вычисляются по порядку, и выполняется первая подошедшая. Поэтому более частые типы разумно ставить выше — это упрощает чтение и слегка сокращает вычисления, хотя на производительность больших выборок порядок веток влияет незначительно.

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

Приведение типа функцией ВЫРАЗИТЬ

ВЫРАЗИТЬ решает обратную задачу: не проверяет тип, а приводит значение к нему. Если значение уже нужного типа — оно возвращается как есть; если тип другой — результат NULL. Это позволяет безопасно «открыть» составное поле:

ВЫБРАТЬ

ВЫРАЗИТЬ(Заказ.Договор КАК Справочник.ДоговорыКонтрагентов).ВалютаВзаиморасчётов КАК Валюта

ИЗ

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

Приведение к примитивным типам работает иначе: ВЫРАЗИТЬ(Поле КАК Строка(50)) обрезает строку до указанной длины, ВЫРАЗИТЬ(Поле КАК Число(15, 2)) приводит число к заданной точности. Для типа Дата указание части даты (Дата, Время, ДатаВремя) также поддерживается.

Типичный сценарий — отбор по реквизиту составного поля. Нельзя написать ГДЕ СоставноеПоле.Артикул = "А-1" напрямую, но можно: ГДЕ ВЫРАЗИТЬ(СоставноеПоле КАК Справочник.Номенклатура).Артикул = "А-1". Записи, где поле другого типа, дадут NULL и не пройдут условие — это ожидаемое поведение.

Проверка типа параметра и значения NULL

Когда тип нужно проверить у параметра запроса, подход тот же: ТИПЗНАЧЕНИЯ(&Параметр) = ТИП(Справочник.Номенклатура). Это полезно в универсальных отчётах, где один параметр может принимать разные объекты. Учтите, что если параметр не инициализирован или равен NULL, ТИПЗНАЧЕНИЯ вернёт тип NULL, и сравнение с любым конкретным типом даст Ложь.

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

Ещё один нюанс — неопределённое значение типа «Неопределено» из кода в запрос попадает как NULL. Поэтому логику «тип не совпал» и «значение пустое» стоит разделять явно, особенно в отчётах, где пользователь может оставить отбор пустым.

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

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

Запрос выполняется без ошибок
Норма

В консоли запросов результат выводится, нет сообщения о несовместимых типах

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

Ошибка «Несовместимые типы» или «Поле не найдено» при обращении к реквизиту

Отбор по типу
Норма

В результат попадают только записи с нужным типом значения

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

Выборка пустая, хотя данные с нужным типом точно есть — проверьте имя типа в литерале ТИП()

Обработка NULL
Норма

Незаполненные поля попадают в ветку ИНАЧЕ или отдельное условие ЕСТЬ NULL

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

Записи с пустым полем теряются или попадают не в ту категорию

Типичные ошибки при сравнении типов

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

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

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

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

Производительность и ограничения

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

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

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

Итог

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

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

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

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

ТИПЗНАЧЕНИЯ возвращает тип любого значения, включая примитивные (Число, Строка, Дата, Булево), и результат нужно сравнивать с литералом ТИП(). Оператор ССЫЛКА сразу возвращает Истина или Ложь, но работает только со ссылочными типами. Для ссылок оба способа равнозначны, ССЫЛКА просто короче.

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

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

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

Значит, фактический тип значения не совпадает с типом приведения. Например, поле хранит ссылку на справочник «Сотрудники», а вы приводите его к «Контрагенты». Проверьте состав типа поля в конфигураторе и фактические данные — сначала отфильтруйте записи по типу, потом приводите.

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

Так же, как тип поля: ТИПЗНАЧЕНИЯ(&Параметр) = ТИП(Справочник.Номенклатура). Если параметр равен NULL или Неопределено, сравнение даст Ложь — при необходимости добавьте отдельную ветку обработки пустого параметра.

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

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

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

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