Типы значений в языке запросов 1С: ТИПЗНАЧЕНИЯ, ТИП, ВЫРАЗИТЬ и ССЫЛКА
Содержание
Чтобы сравнить тип значения прямо в запросе 1С, используют функцию ТИПЗНАЧЕНИЯ() и сравнивают её результат с нужным типом через ТИП():
ГДЕ ТИПЗНАЧЕНИЯ(Таблица.Поле) = ТИП(Справочник.Номенклатура). Для ссылочных типов короче и читаемее оператор ССЫЛКА.
Сравнение типов данных в запросе нужно там, где поле может хранить значения разных типов: регистратор в регистре, поле «Предмет» задачи, реквизит с составным типом. Платформа 8.3 даёт для этого три инструмента — проверку типа, оператор ССЫЛКА и приведение ВЫРАЗИТЬ. Ниже — когда какой применять, как не перепутать Неопределено с NULL и почему неверное обращение к составному полю замедляет запрос в разы.
Сразу уберём частую путаницу. В модуле (встроенный язык) тип значения возвращает функция ТипЗнч(). В языке запросов её нет — там работает ТИПЗНАЧЕНИЯ(). Если написать ТипЗнч внутри текста запроса, конструктор выдаст ошибку синтаксиса.
Чем в запросе определить и сравнить тип значения
В языке запросов 1С 8.3 за типы отвечают две функции:
- 🔹
ТИПЗНАЧЕНИЯ(<выражение>)— возвращает тип переданного значения. - 🔹
ТИП(<имя типа>)— возвращает сам тип по его имени, чтобы было с чем сравнивать.
Сравнение строится как равенство результатов этих функций:
ВЫБРАТЬ
Остатки.Регистратор,
Остатки.Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Остатки
ГДЕ
ТИПЗНАЧЕНИЯ(Остатки.Регистратор) = ТИП(Документ.ПоступлениеТоваровУслуг)
В аргумент ТИП() подставляют как ссылочные типы, так и примитивные:
| Что проверяем | Как записать |
|---|---|
| Ссылка на справочник | ТИП(Справочник.Номенклатура) |
| Ссылка на документ | ТИП(Документ.РеализацияТоваровУслуг) |
| Элемент перечисления | ТИП(Перечисление.СтавкиНДС) |
| Строка | ТИП(Строка) |
| Число | ТИП(Число) |
| Дата | ТИП(Дата) |
| Булево | ТИП(Булево) |
ТИПЗНАЧЕНИЯ удобна именно тем, что работает с любым типом. Если поле составное и может хранить то строку, то число, то ссылку — это единственный способ разложить его по типам в одном запросе.
Оператор ССЫЛКА для ссылочных типов
Когда проверяемое поле хранит ссылку, вместо пары ТИПЗНАЧЕНИЯ = ТИП чаще берут оператор ССЫЛКА. Он возвращает Истина, если значение — ссылка указанного типа:
ГДЕ
Остатки.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
Две записи ниже дают одинаковый результат, но вторая короче и читается как обычное условие:
// через функции
ГДЕ ТИПЗНАЧЕНИЯ(Остатки.Регистратор) = ТИП(Документ.ПоступлениеТоваровУслуг)
// через оператор ССЫЛКА
ГДЕ Остатки.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
Разница в области применения:
- ✅
ССЫЛКА— только для ссылочных типов (справочники, документы, планы видов характеристик и т. п.). - ✅
ТИПЗНАЧЕНИЯ = ТИП— для любых типов, включая примитивныеСтрока,Число,Дата.
Для отрицания ставят НЕ перед всем выражением: ГДЕ НЕ Остатки.Регистратор ССЫЛКА Документ.СписаниеТоваров.
Поля составного типа и приведение через ВЫРАЗИТЬ
Поле составного типа само по себе не даёт обратиться к реквизитам конкретного объекта. Нельзя просто написать Остатки.Регистратор.Склад: платформа не знает заранее, документ какого вида лежит в поле, и у разных документов разный набор реквизитов.
Здесь нужно приведение типа — функция ВЫРАЗИТЬ(<выражение> КАК <тип>). Она сообщает платформе: «рассматривай это значение как объект такого-то типа», после чего становятся доступны его реквизиты:
ВЫБРАТЬ
Остатки.Регистратор,
ВЫРАЗИТЬ(Остатки.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Склад КАК Склад,
Остатки.Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК Остатки
ГДЕ
Остатки.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
Логика связки такая:
- В условии
ГДЕоператоромССЫЛКАотбираем только записи нужного вида документа. - В списке полей функцией
ВЫРАЗИТЬприводим составной регистратор к этому виду и читаем его реквизитСклад.
Если значение окажется не того типа, который указан в ВЫРАЗИТЬ, функция вернёт NULL, а не ошибку. Поэтому отбор по типу в ГДЕ и приведение в полях должны указывать один и тот же тип — иначе в колонке будут пустые 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.