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