При работе со сложными запросами в системе 1С:Предприятие часто возникает задача динамической проверки типа данных. Особенно остро этот вопрос стоит при использовании механизма Дополнительных сведений или при обработке данных из временных таблиц, где тип объекта может храниться в виде строки или определяться в процессе выполнения. Рассмотрим подробнее, как эффективно решать подобные задачи, проанализируем различные подходы и выберем оптимальные методы для разных сценариев.
Представим типичную ситуацию: у нас есть временная таблица ВТ_ТабЗнач, содержащая колонки с данными и строковое представление типа реквизита (например, "Справочник.Склады"). Нам необходимо выполнить ЛЕВОЕ СОЕДИНЕНИЕ с регистром сведений ДополнительныеСведения так, чтобы условие связи проверяло не только равенство значений, но и соответствие типа объекта в регистре тому типу, который указан в нашей таблице.
Разберем первый подход, который часто применяется, когда имя типа известно только на этапе исполнения программного кода. Оператор ССЫЛКА в языке запросов 1С является очень быстрым, но он не принимает параметры. Поэтому нам придется прибегнуть к модификации строки запроса.
Проанализируем пример реализации:
// В коде 1С формируем условие
ТипРеквизита = "Справочник.Склады"; // Получено динамически
УсловиеТипа = " И ДопСвед.Объект ССЫЛКА " + ТипРеквизита;
ТекстЗапроса = "ВЫБРАТЬ ...
|ИЗ ВТ_ТабЗнач КАК ВТ_ТабЗнач
|ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСвед
|ПО ВТ_ТабЗнач.Тип_цифра = ДопСвед.Значение
|И ДопСвед.Свойство.Наименование = ВТ_ТабЗнач.Свойство
|&УсловиеТипа";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеТипа", УсловиеТипа);
Важный нюанс: использование оператора ССЫЛКА позволяет платформе оптимизировать SQL-запрос, так как она заранее знает, к какой физической таблице обращаться. Однако этот метод требует осторожности при работе со строками, чтобы избежать синтаксических ошибок в запросе.
Если в нашей временной таблице уже есть поле с эталонным объектом нужного типа, мы можем использовать встроенную функцию ТИПЗНАЧЕНИЯ. Это делает запрос более универсальным и избавляет от необходимости манипуляций со строками.
Посмотрим на пример условия в запросе:
|ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСвед
|ПО ВТ_ТабЗнач.Тип_цифра = ДопСвед.Значение
|И (ДопСвед.Свойство.Наименование = ВТ_ТабЗнач.Свойство)
|И (ТИПЗНАЧЕНИЯ(ДопСвед.Объект) = ТИПЗНАЧЕНИЯ(ВТ_ТабЗнач.Реквизит))
В данном случае мы сравниваем типы двух полей. Если ВТ_ТабЗнач.Реквизит содержит пустую ссылку нужного нам типа, условие сработает корректно. Выясним причину популярности этого метода: он позволяет обрабатывать сразу несколько типов в одном пакете запроса без динамической сборки текста.
Рассмотрим ситуацию, когда нам нужно отфильтровать данные по конкретному типу, который мы можем вычислить в коде 1С с помощью встроенных функций метаданных. Мы можем передать сам тип как объект Тип в параметр запроса.
Пример программной подготовки:
Запрос.УстановитьПараметр("НужныйТип", Тип("Справочник.Склады"));
И использование в тексте запроса:
ГДЕ ТИПЗНАЧЕНИЯ(ДопСвед.Объект) = &НужныйТип
Этот способ объединяет в себе чистоту кода и гибкость. Мы не меняем текст запроса «на лету», что упрощает отладку и поддержку кода.
Если тип объекта известен заранее и не меняется, мы можем прописать его прямо в тексте запроса, используя конструкцию ЗНАЧЕНИЕ. Это наиболее производительный и читаемый вариант для статических условий.
ВЫБОР
КОГДА ТИПЗНАЧЕНИЯ(ДопСвед.Объект) = ЗНАЧЕНИЕ(Тип.Справочник.Склады)
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК ЭтоСклад
Проанализируем важный технический аспект: использование функций над полями в условиях ПО или ГДЕ. Когда мы пишем ТИПЗНАЧЕНИЯ(ДопСвед.Объект), СУБД (например, MS SQL Server или PostgreSQL) зачастую не может эффективно использовать индексы по полю Объект. Это может привести к замедлению работы на больших таблицах (миллионы записей в дополнительных сведениях).
Для оптимизации рекомендуется использовать конструкцию ВЫРАЗИТЬ. Посмотрим, как это работает:
ВЫБРАТЬ
ДопСвед.Объект КАК Объект
ИЗ
РегистрСведений.ДополнительныеСведения КАК ДопСвед
ГДЕ
ВЫРАЗИТЬ(ДопСвед.Объект КАК Справочник.Склады) ЕСТЬ НЕ NULL
Почему это быстрее? Оператор ВЫРАЗИТЬ работает на уровне типизации платформы более жестко и помогает оптимизатору запросов сузить круг поиска до конкретной таблицы справочника.
При использовании ЛЕВОЕ СОЕДИНЕНИЕ важно помнить, что если запись в правой таблице не найдена, функция ТИПЗНАЧЕНИЯ(NULL) вернет NULL. Проанализируем типичную ошибку: попытка сравнения типа в блоке ГДЕ после левого соединения может случайно отсечь все записи, где соединение не произошло. Если ваша задача — сохранить все строки из ВТ_ТабЗнач, всегда проверяйте условия на тип либо внутри условия ПО, либо учитывайте NULL в блоке ГДЕ.
ССЫЛКА (через замену текста) или ВЫРАЗИТЬ.ТИПЗНАЧЕНИЯ с передачей типа в параметре.ЗНАЧЕНИЕ(Тип.ИмяМетаданных).Рассмотренные подходы позволяют гибко управлять типизацией в запросах 1С, обеспечивая баланс между производительностью системы и чистотой программного кода.