Как определить тип реквизита в запросе 1С и использовать его в условиях

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Постановка задачи

Представим типичную ситуацию: у нас есть временная таблица ВТ_ТабЗнач, содержащая колонки с данными и строковое представление типа реквизита (например, "Справочник.Склады"). Нам необходимо выполнить ЛЕВОЕ СОЕДИНЕНИЕ с регистром сведений ДополнительныеСведения так, чтобы условие связи проверяло не только равенство значений, но и соответствие типа объекта в регистре тому типу, который указан в нашей таблице.

Способ 1. Динамическое формирование текста запроса

Разберем первый подход, который часто применяется, когда имя типа известно только на этапе исполнения программного кода. Оператор ССЫЛКА в языке запросов 1С является очень быстрым, но он не принимает параметры. Поэтому нам придется прибегнуть к модификации строки запроса.

Проанализируем пример реализации:


// В коде 1С формируем условие
ТипРеквизита = "Справочник.Склады"; // Получено динамически
УсловиеТипа = " И ДопСвед.Объект ССЫЛКА " + ТипРеквизита;

ТекстЗапроса = "ВЫБРАТЬ ... 
               |ИЗ ВТ_ТабЗнач КАК ВТ_ТабЗнач
               |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСвед
               |ПО ВТ_ТабЗнач.Тип_цифра = ДопСвед.Значение
               |И ДопСвед.Свойство.Наименование = ВТ_ТабЗнач.Свойство
               |&УсловиеТипа";

ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеТипа", УсловиеТипа);

Важный нюанс: использование оператора ССЫЛКА позволяет платформе оптимизировать SQL-запрос, так как она заранее знает, к какой физической таблице обращаться. Однако этот метод требует осторожности при работе со строками, чтобы избежать синтаксических ошибок в запросе.

Способ 2. Использование функции ТИПЗНАЧЕНИЯ

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

Посмотрим на пример условия в запросе:


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

В данном случае мы сравниваем типы двух полей. Если ВТ_ТабЗнач.Реквизит содержит пустую ссылку нужного нам типа, условие сработает корректно. Выясним причину популярности этого метода: он позволяет обрабатывать сразу несколько типов в одном пакете запроса без динамической сборки текста.

Способ 3. Передача типа через параметры

Рассмотрим ситуацию, когда нам нужно отфильтровать данные по конкретному типу, который мы можем вычислить в коде 1С с помощью встроенных функций метаданных. Мы можем передать сам тип как объект Тип в параметр запроса.

Пример программной подготовки:


Запрос.УстановитьПараметр("НужныйТип", Тип("Справочник.Склады"));

И использование в тексте запроса:


ГДЕ ТИПЗНАЧЕНИЯ(ДопСвед.Объект) = &НужныйТип

Этот способ объединяет в себе чистоту кода и гибкость. Мы не меняем текст запроса «на лету», что упрощает отладку и поддержку кода.

Способ 4. Использование литерала ЗНАЧЕНИЕ(Тип...)

Если тип объекта известен заранее и не меняется, мы можем прописать его прямо в тексте запроса, используя конструкцию ЗНАЧЕНИЕ. Это наиболее производительный и читаемый вариант для статических условий.


ВЫБОР
    КОГДА ТИПЗНАЧЕНИЯ(ДопСвед.Объект) = ЗНАЧЕНИЕ(Тип.Справочник.Склады)
        ТОГДА 1
    ИНАЧЕ 0
КОНЕЦ КАК ЭтоСклад

Производительность и SARGability (индексируемость)

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

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


ВЫБРАТЬ
    ДопСвед.Объект КАК Объект
ИЗ
    РегистрСведений.ДополнительныеСведения КАК ДопСвед
ГДЕ
    ВЫРАЗИТЬ(ДопСвед.Объект КАК Справочник.Склады) ЕСТЬ НЕ NULL

Почему это быстрее? Оператор ВЫРАЗИТЬ работает на уровне типизации платформы более жестко и помогает оптимизатору запросов сузить круг поиска до конкретной таблицы справочника.

Особенности работы с NULL

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

Резюме по выбору метода

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

Рассмотренные подходы позволяют гибко управлять типизацией в запросах 1С, обеспечивая баланс между производительностью системы и чистотой программного кода.

← На главную