Как правильно использовать оператор ПОДОБНО с параметром в запросе 1С

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

При разработке отчетов и обработок часто возникает задача найти данные по фрагменту строки, который вводит пользователь. Начинающие разработчики нередко сталкиваются с ошибками синтаксиса, пытаясь поместить имя параметра прямо внутрь строкового литерала, например: ПОДОБНО "%[&Текст]%". Разберем по шагам, почему такая конструкция не работает, как правильно сформировать шаблон поиска и какие нюансы следует учитывать для обеспечения максимального быстродействия запроса.

Причина ошибки и базовый синтаксис оператора ПОДОБНО

В языке запросов 1С литерал строки заключается в двойные кавычки. Если поместить конструкцию &Текст внутрь кавычек, транслятор запросов воспримет ее не как параметр, а как обычный статичный текст: знак процента, открывающуюся квадратную скобку, амперсанд, слово «Текст», закрывающуюся скобку и второй знак процента. В результате запрос будет искать буквальное совпадение с этой строкой, а не с тем значением, которое передал пользователь.

Оператор ПОДОБНО сравнивает строковое поле с шаблоном. В шаблоне используются следующие управляющие знаки:

  1. Знак процента (%) — обозначает любую последовательность из нуля или более произвольных символов.
  2. Знак подчеркивания (_) — обозначает ровно один произвольный символ.
  3. Квадратные скобки ([...]) — задают диапазон или перечень допустимых одиночных символов.

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

Способ 1. Конкатенация строки непосредственно в тексте запроса

Рассмотрим вариант, когда шаблон формируется прямо в секции условий запроса с помощью оператора сложения строк +. В этом случае символы маски берутся в кавычки, а имя параметра указывается без кавычек:


ВЫБРАТЬ
    Автомобили.Значение КАК Значение,
    РеализацияТоваровУслуг.Ссылка КАК Ссылка
ИЗ
    РегистрСведений.Автомобили КАК Автомобили
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        ПО Автомобили.Автомобиль = РеализацияТоваровУслуг.Автомобиль
ГДЕ
    Автомобили.ВидЗначения = &ГосНомер
    И Автомобили.Значение ПОДОБНО "%" + &Текст + "%"

Этот вариант нагляден, однако у него есть недостаток: конкатенация строк переносится в план выполнения запроса на стороне СУБД, что может слегка усложнить оптимизацию плана SQL.

Способ 2. Подготовка шаблона во встроенном языке (рекомендуемый)

Проанализируем более эффективный и надежный способ. Лучшей практикой в разработке на платформе 1С считается вычисление полного шаблона поиска на стороне встроенного языка 1С до передачи в запрос. Это упрощает текст запроса и снижает нагрузку на СУБД.

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


// Формируем строку шаблона во встроенном языке
ШаблонПоиска = "%" + СокрЛП(ТекстПользователя) + "%";

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

Запрос.УстановитьПараметр("ГосНомер", ВидЗначенияГосНомер);
Запрос.УстановитьПараметр("ШаблонПоиска", ШаблонПоиска);

Результат = Запрос.Выполнить();

Оптимизация обращений к полям и предотвращение лишних соединений

Обратим внимание на частую ошибку в условиях: использование конструкции вида Автомобили.Автомобиль = РеализацияТоваровУслуг.Автомобиль.Ссылка или Автомобили.ВидЗначения.Ссылка = &ГосНомер.

В платформе 1С реквизит Автомобиль уже хранит ссылку. Обращение через точку к свойству .Ссылка у ссылочного поля приводит к неявному разыменованию — генератор запросов 1С добавит в SQL-запрос дополнительное левое соединение (LEFT JOIN) с таблицей справочника ради получения той же самой ссылки. Сравнивайте ссылочные поля напрямую: Автомобили.ВидЗначения = &ГосНомер.

Работа с типами данных и строками неограниченной длины

Оператор ПОДОБНО может быть применен только к строковым данным. Если поле в базе данных имеет составной тип (например, строка, число или ссылка), выполнение запроса завершится ошибкой или вернет некорректный результат.

Если поле составное, необходимо обязательно ограничить тип и длину:

  1. Либо отфильтровать тип в условии: ГДЕ ТИПЗНАЧЕНИЯ(Автомобили.Значение) = ТИП(Строка).
  2. Либо явно привести тип с помощью функции ВЫРАЗИТЬ: И ВЫРАЗИТЬ(Автомобили.Значение КАК Строка(150)) ПОДОБНО &ШаблонПоиска

Помните, что поиск по строкам неограниченной длины существенно замедляет выполнение запроса на уровне СУБД, поэтому рекомендуется всегда приводить их к фиксированной длине.

Экранирование спецсимволов при пользовательском вводе

Если пользователь введет в строку поиска символ процента %, подчеркивание _ или квадратную скобку [, платформа воспримет их как маску шаблона. Чтобы выполнить поиск именно этих символов как обычного текста, используйте конструкцию СПЕЦСИМВОЛ:


// В запросе указывается символ экранирования, например обратный слэш:
И Автомобили.Значение ПОДОБНО &ШаблонПоиска СПЕЦСИМВОЛ "\"

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


Текст = СтрЗаменить(ТекстПользователя, "\", "\\");
Текст = СтрЗаменить(Текст, "%", "\%");
Текст = СтрЗаменить(Текст, "_", "\_");
ШаблонПоиска = "%" + Текст + "%";

Влияние на производительность и индексы

Посмотрим, как оператор ПОДОБНО влияет на работу СУБД. Наличие знака % в самом начале шаблона ("%Текст%") делает условие неселективным для индексов (Non-SARGable). СУБД физически не может применить индекс по строковому полю и будет вынуждена сканировать всю таблицу целиком (Table Scan или Index Scan). На больших таблицах это приводит к медленной работе запроса и избыточным блокировкам.

Если по бизнес-требованиям допустимо искать данные только с начала строки, всегда формируйте шаблон как Текст + "%". В этом случае СУБД выполнит эффективный поиск по индексу (Index Seek).

Если же требуется частый полнотекстовый поиск по фрагментам в больших объемах данных, оптимальнее использовать встроенный в платформу механизм полнотекстового поиска (объект ПолнотекстовыйПоиск) либо создавать специальные регистры поиска со словами фиксированной длины.

← На главную