При выполнении запросов к базе данных 1С часто возникает задача найти строки, содержащие определенный текст, например, наименования номенклатуры с техническими характеристиками, артикулами или маркировкой в квадратных скобках вида 1[mu]. Однако при использовании стандартной конструкции ПОДОБНО "%1[mu]%" разработчик может столкнуться с тем, что запрос возвращает пустой результат, даже если соответствующие данные присутствуют в информационной базе. Разберем причины такого поведения и рассмотрим все доступные варианты решения этой задачи.
Проанализируем работу оператора ПОДОБНО в языке запросов 1С:Предприятия. Данный оператор выполняет сопоставление строки с шаблоном, в котором зарезервирован ряд специальных управляющих символов:
%) — обозначает последовательность любых символов произвольной длины (включая нулевую длину)._) — обозначает ровно один произвольный символ.[...]) — обозначают любой одиночный символ из перечисленных внутри скобок. Например, шаблон [абв] означает либо «а», либо «б», либо «в», а шаблон [0-9] задает диапазон цифр от 0 до 9.[^...]) — обозначает любой одиночный символ, кроме перечисленных внутри скобок.Когда мы передаем в условие шаблон "%1[mu]%", СУБД воспринимает конструкцию [mu] не как текстовые символы скобок и букв, а как условие: «символ "1", за которым следует ровно один символ — либо "m", либо "u"». Соответственно, строка "1[mu]" не удовлетворяет этому шаблону, и запрос возвращает пустую выборку.
Основной способ сказать платформе, что символ должен восприниматься как обычный текст, — применить конструкцию СПЕЦСИМВОЛ (в SQL-синтаксисе аналог ESCAPE). В качестве спецсимвола можно назначить любой не используемый в поисковой фразе знак, например, слэш /, обратный слэш \ или восклицательный знак !.
Посмотрим на пример запроса, где мы экранируем квадратные скобки с помощью символа /:
ВЫБРАТЬ
"1[mu]" КАК П
ПОМЕСТИТЬ ВТ_Данные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.П КАК ПолеСтрока
ИЗ
ВТ_Данные КАК ВТ
ГДЕ
ВТ.П ПОДОБНО "%1/[mu/]%" СПЕЦСИМВОЛ "/"
В этом примере перед открывающей скобкой [ и закрывающей скобкой ] ставится указанный спецсимвол экранирования. СУБД воспринимает последовательности /[ и /] как обычные литералы скобок, и строка успешно находится.
В языке шаблонов открывающая квадратная скобка [ служит открывающим маркером диапазона. Поэтому ее можно экранировать без явного указания директивы СПЕЦСИМВОЛ, просто заключив открывающую скобку в еще одни квадратные скобки: [[]. Закрывающая скобка ] вне диапазона не открывает условий и может не экранироваться.
Рассмотрим, как выглядит такой шаблон:
ВЫБРАТЬ
ВТ.П КАК ПолеСтрока
ИЗ
ВТ_Данные КАК ВТ
ГДЕ
ВТ.П ПОДОБНО "%1[[]mu]%"
Этот вариант удобен для простых статичных шаблонов, но при программной генерации строк проще и надежнее использовать метод явного экранирования через СПЕЦСИМВОЛ.
Начиная с платформы 1С:Предприятие 8.3.20, в языке запросов появилась встроенная функция СТРНАЙТИ, которая транслируется на уровне СУБД в соответствующие строковые функции (такие как CHARINDEX или STRPOS). Если требуется найти точное вхождение подстроки без использования шаблонов подстановки, этот способ наиболее лаконичен, так как не требует экранирования спецсимволов.
Разберем пример запроса с передачей искомого значения через параметр:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| СТРНАЙТИ(Номенклатура.Наименование, &ИскомыйФрагмент) > 0";
Запрос.УстановитьПараметр("ИскомыйФрагмент", "1[mu]");
Результат = Запрос.Выполнить();
В данном случае строка "1[mu]" передается как есть, и платформа ищет точное совпадение фрагмента в поле Наименование.
Если строка поиска вводится пользователем интерактивно и передается в условие с оператором ПОДОБНО, в ней могут присутствовать любые спецсимволы (%, _, [, а также сам символ экранирования). Чтобы поиск работал стабильно, выполним правильную подготовку шаблона на встроенном языке.
Разберем по шагам алгоритм экранирования:
/ на //).% на /%._ на /_.[ на /[.Посмотрим на пример функции для экранирования пользовательской строки:
Функция ПодготовитьСтрокуДляПодобно(Знач ИсходныйТекст, Знач СимволЭкранирования = "/") Экспорт
// 1. Удваиваем сам символ экранирования
Результат = СтрЗаменить(ИсходныйТекст, СимволЭкранирования, СимволЭкранирования + СимволЭкранирования);
// 2. Экранируем спецсимволы ПОДОБНО
Результат = СтрЗаменить(Результат, "%", СимволЭкранирования + "%");
Результат = СтрЗаменить(Результат, "_", СимволЭкранирования + "_");
Результат = СтрЗаменить(Результат, "[", СимволЭкранирования + "[");
// 3. Добавляем знаки поиска по вхождению
Возврат "%" + Результат + "%";
КонецФункции
При использовании строкового поиска в запросах 1С необходимо учитывать технические особенности СУБД:
Строка неограниченной длины, к нему нельзя напрямую применить операторы ПОДОБНО или функцию СТРНАЙТИ. Необходимо предварительно ограничить длину с помощью функции ПОДСТРОКА(Поле, 1, 1000).ПОДОБНО "%значение%" (с ведущим знаком процента) или СТРНАЙТИ(...) > 0 не могут использовать стандартные индексы СУБД по строковым полям. Это приводит к полному сканированию таблицы (Table Scan). Для высоконагруженных систем и больших справочников рекомендуется использовать встроенный полнотекстовый поиск 1С.