Типы значений в языке запросов 1С: ТИПЗНАЧЕНИЯ, ТИП, ВЫРАЗИТЬ и ССЫЛКА

· 9 мин

Содержание

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

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

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

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

В языке запросов 1С 8.3 за типы отвечают две функции:

  • 🔹 ТИПЗНАЧЕНИЯ(<выражение>) — возвращает тип переданного значения.
  • 🔹 ТИП(<имя типа>) — возвращает сам тип по его имени, чтобы было с чем сравнивать.

Сравнение строится как равенство результатов этих функций:

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

В аргумент ТИП() подставляют как ссылочные типы, так и примитивные:

Что проверяемКак записать
Ссылка на справочникТИП(Справочник.Номенклатура)
Ссылка на документТИП(Документ.РеализацияТоваровУслуг)
Элемент перечисленияТИП(Перечисление.СтавкиНДС)
СтрокаТИП(Строка)
ЧислоТИП(Число)
ДатаТИП(Дата)
БулевоТИП(Булево)

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

Оператор ССЫЛКА для ссылочных типов

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

ГДЕ
    Остатки.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг

Две записи ниже дают одинаковый результат, но вторая короче и читается как обычное условие:

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

// через оператор ССЫЛКА
ГДЕ Остатки.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг

Разница в области применения:

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

Для отрицания ставят НЕ перед всем выражением: ГДЕ НЕ Остатки.Регистратор ССЫЛКА Документ.СписаниеТоваров.

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

Поле составного типа само по себе не даёт обратиться к реквизитам конкретного объекта. Нельзя просто написать Остатки.Регистратор.Склад: платформа не знает заранее, документ какого вида лежит в поле, и у разных документов разный набор реквизитов.

Здесь нужно приведение типа — функция ВЫРАЗИТЬ(<выражение> КАК <тип>). Она сообщает платформе: «рассматривай это значение как объект такого-то типа», после чего становятся доступны его реквизиты:

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

Логика связки такая:

  1. В условии ГДЕ оператором ССЫЛКА отбираем только записи нужного вида документа.
  2. В списке полей функцией ВЫРАЗИТЬ приводим составной регистратор к этому виду и читаем его реквизит Склад.

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

Тот же приём работает и для составных реквизитов справочников и документов (например, поле «Основание», «Контрагент» с составным типом) — не только для регистраторов.

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

Составной тип в метаданных: что вообще можно сравнивать

Поле получает составной тип в конфигураторе: в свойстве «Тип» реквизита или ресурса отмечают несколько типов галочками. Сравнивать в запросе можно только с теми типами, что заданы в метаданных поля. Если документа нет в списке типов регистратора, условие ССЫЛКА на него всегда даст ложь — и это не ошибка, а следствие описания метаданных.

Где составной тип встречается чаще всего:

  • 🗂 Регистратор регистров накопления, сведений и бухгалтерии — набор типов собирается автоматически из всех документов, которые пишут движения в этот регистр.
  • 🗂 Предмет и основание задач и бизнес-процессов.
  • 🗂 Реквизиты справочников и документов с составным типом (например, поле, где контрагентом может быть и организация, и физлицо).
  • 🗂 Значение характеристики через план видов характеристик — там тип вообще меняется от строки записи.

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

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

Неопределено, NULL и пустая ссылка — три разных «пусто»

Самая частая причина, по которой условие на тип «не срабатывает», — путаница между тремя непохожими значениями. Они выглядят как «ничего», но проверяются по-разному.

  • 🟡 Неопределено — значение незаполненного поля составного типа. Поле есть, но в него ничего не положили.
  • 🔴 NULL — отсутствие данных. Появляется, когда левое соединение не нашло пару, или когда ВЫРАЗИТЬ привёл значение к неподходящему типу.
  • ⚪ Пустая ссылка — заполненное поле ссылочного типа с «пустым» значением (например, пустая ссылка на номенклатуру). Это не Неопределено и не NULL.

Проверяют их разными конструкциями:

// незаполненное составное поле
ГДЕ Таблица.Основание <> Неопределено

// нет данных после соединения
ГДЕ Остатки.КоличествоОстаток ЕСТЬ NULL
ГДЕ Остатки.КоличествоОстаток ЕСТЬ НЕ NULL

// пустая ссылка справочника/документа
ГДЕ Таблица.Контрагент <> ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

Для подстановки значения вместо NULL служит функция ЕСТЬNULL(<выражение>, <значение по умолчанию>) — особенно в запросах с левым соединением к остаткам регистров:

ВЫБРАТЬ
    Ном.Ссылка КАК Номенклатура,
    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
    Справочник.Номенклатура КАК Ном
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
    ПО Остатки.Номенклатура = Ном.Ссылка

Сравнение с NULL через = всегда даёт NULL (то есть «не истина»). Запись ГДЕ Поле = NULL не отберёт ничего. Для NULL используйте только операторы ЕСТЬ NULL и ЕСТЬ НЕ NULL.

Производительность: почему ВЫРАЗИТЬ ускоряет запрос

Обращение к реквизиту составного поля без приведения типа — главная скрытая причина медленных запросов. Разберём механизм.

Когда вы пишете Остатки.Регистратор.Дата, а регистратор имеет составной тип из, скажем, десяти видов документов, платформа не знает, в какую таблицу идти за реквизитом Дата. Поэтому в SQL она добавляет левое соединение со всеми таблицами всех типов регистратора и собирает результат. Десять видов документов — до десяти лишних соединений на одно поле.

ВЫРАЗИТЬ снимает неопределённость: тип указан явно, и соединение остаётся одно.

// медленно: соединение со всеми таблицами типов регистратора
ВЫБРАТЬ Остатки.Регистратор.Дата КАК ДатаДок ...

// быстро: одно соединение с указанной таблицей
ВЫБРАТЬ ВЫРАЗИТЬ(Остатки.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Дата КАК ДатаДок ...

Что это даёт и о чём помнить:

  • ⚡ Чем больше типов в составном поле, тем сильнее выигрыш от ВЫРАЗИТЬ.
  • ⚡ Отбор по типу в ГДЕ оператором ССЫЛКА отсекает лишние записи до вычисления полей — ставьте его.
  • ⚡ Для отбора по одному типу ССЫЛКА и ТИПЗНАЧЕНИЯ = ТИП для оптимизатора равнозначны; выбирайте по читаемости.

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

Примеры фильтрации по типу

Несколько готовых шаблонов под типовые задачи.

Отобрать из регистра движения только одного вида документа:

ВЫБРАТЬ
    Движения.Регистратор,
    Движения.Номенклатура,
    Движения.Количество
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК Движения
ГДЕ
    Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Разложить составное поле по типам в одной колонке (через выбор ВЫБОР … КОГДА):

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

Отобрать строки, где составной реквизит заполнен:

ГДЕ Документы.Основание <> Неопределено

Отобрать значения конкретного примитивного типа (поле произвольного типа хранит и строки, и числа):

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

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

  • ❌ ТипЗнч вместо ТИПЗНАЧЕНИЯ. Функция из модуля не работает в тексте запроса — конструктор запросов подчеркнёт её как ошибку.
  • ❌ Сравнение с NULL через знак равенства. ГДЕ Поле = NULL не отбирает ничего. Нужен оператор ЕСТЬ NULL.
  • ❌ Разные типы в ГДЕ и в ВЫРАЗИТЬ. Отобрали ПоступлениеТоваровУслуг, а привели к РеализацииТоваровУслуг — колонка заполнится NULL.
  • ❌ Обращение к реквизиту составного поля без приведения. Работает, но тащит соединения со всеми таблицами типов и роняет скорость.
  • ❌ Путаница Неопределено и пустой ссылки. Незаполненное составное поле — это Неопределено; пустая ссылка справочника — заполненное значение, их нельзя проверять одним условием.

Если ВЫРАЗИТЬ неожиданно возвращает пустые значения — первым делом сверьте тип в приведении с типом в отборе. В 90% случаев причина именно в их расхождении.

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

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