В языке запросов 1С существует мощный инструмент для поиска по строковым шаблонам — оператор ПОДОБНО. Для работы со служебными символами, такими как процент (%) или подчеркивание (_), стандарт предусматривает использование конструкции СПЕЦСИМВОЛ (или ESCAPE). Однако при использовании объекта ПостроительЗапроса разработчики часто сталкиваются с тем, что привычные методы экранирования не работают. В этой статье мы разберем, почему это происходит и как правильно организовать поиск спецсимволов в отборах построителя.
Рассмотрим ситуацию: нам необходимо найти в информационной базе строки, содержащие символ подчеркивания (_). Если мы используем прямой запрос, мы можем написать конструкцию ПОДОБНО "%~_%" СПЕЦСИМВОЛ "~". Но когда мы работаем через ПостроительЗапроса, мы взаимодействуем с коллекцией Отбор. Платформа автоматически транслирует установленные элементы отбора в текст запроса.
Проблема заключается в том, что механизмы автоматической генерации запросов в объектах ПостроительЗапроса и даже в Системе компоновки данных (СКД) при использовании вида сравнения Содержит, Начинается с или Подобно жестко преобразуют значение в шаблон для SQL. При этом в интерфейсе программирования этих объектов отсутствует возможность указать символ экранирования. Платформа просто не добавляет ключевое слово СПЕЦСИМВОЛ в итоговый текст, а попытка «подклеить» его в саму строку значения приведет лишь к тому, что запрос будет искать это слово как часть текста.
Разберем основной способ обхода этого ограничения. Вместо использования СПЕЦСИМВОЛ, мы можем воспользоваться встроенным функционалом языка запросов 1С — синтаксисом групп символов в квадратных скобках [...]. Это стандартная возможность регулярных выражений языка запросов, которая позволяет экранировать служебные знаки, заключая их в скобки.
Проанализируем, как это работает на практике. Когда символ помещается внутрь квадратных скобок, он перестает интерпретироваться как метасимвол (подстановка любого символа или любой последовательности) и воспринимается базой данных как обычный литерал.
Рассмотрим пример кода, демонстрирующий это решение для ПостроительЗапроса:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Стр", Новый ОписаниеТипов("Строка"));
ТЗ.Добавить().Стр = "ОбычныйТекст";
ТЗ.Добавить().Стр = "Текст_со_спецсимволом";
ПС = Новый ПостроительЗапроса;
ПС.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);
ЭлементОтбора = ПС.Отбор.Добавить("Стр");
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ВидСравнения = ВидСравнения.Содержит;
// Вместо использования "~_" мы заключаем подчеркивание в скобки
ЭлементОтбора.Значение = "[_]";
ПодходящиеСлова = ПС.Результат.Выгрузить();
Сообщить("Найдено строк: " + ПодходящиеСлова.Количество());
Выясним, как подготовить строку поиска для различных специальных знаков, если мы не можем задействовать СПЕЦСИМВОЛ:
_): Превращается в [_]. В обычном состоянии он означает "любой один символ", но в скобках ищется именно как нижнее подчеркивание.%): Превращается в [%]. Перестает означать "любую последовательность символов".[): Это самый интересный случай. Чтобы найти саму скобку, её нужно экранировать ею же: [[].]): В языке запросов 1С она не является специальным символом, если перед ней не была встречена открывающая скобка. Поэтому её можно указывать просто как ]. Однако для надежности в сложных шаблонах (например, при поиске пары []) рекомендуется шаблон [[]].^): Внутри скобок в начале строки он означает инверсию. Чтобы найти его как символ, используйте [^].-): Означает диапазон (например, [0-9]). Чтобы найти тире как литерал, поместите его в начало или в конец списка внутри скобок: [-abc] или [abc-].Проанализируем ситуацию с точки зрения эффективности базы данных. Важно понимать, что использование конструкций вида ПОДОБНО "%[_]%" (что фактически делает построитель при виде сравнения Содержит) накладывает серьезные ограничения на производительность:
Во-первых, любое условие, начинающееся с процента (или шаблона в скобках), делает невозможным использование индексов SQL-сервером по этому полю. Система будет вынуждена выполнить полное сканирование таблицы (Full Scan), что на больших объемах данных (миллионы строк) приведет к значительным задержкам.
Во-вторых, обработка регулярных выражений в квадратных скобках чуть медленнее, чем поиск по прямому соответствию или простому ESCAPE, так как движок СУБД тратит дополнительные ресурсы на разбор шаблона.
Если задача требует обязательного использования СПЕЦСИМВОЛ (например, для динамического формирования сложных условий), можно прибегнуть к следующему алгоритму:
ПС.Отбор.Добавить().ГДЕ вручную, используя параметры.{ГДЕ ...} для того, чтобы поле оставалось доступным в настройках, но логику сравнения описать самостоятельно.Рассмотрим пример фрагмента запроса для построителя:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка,
СправочникНоменклатура.Наименование
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
{ГДЕ
(СправочникНоменклатура.Наименование ПОДОБНО &ШаблонПоиска СПЕЦСИМВОЛ "~")}
В этом случае вам придется самостоятельно программно подготовить переменную &ШаблонПоиска, добавив в неё нужные символы % и заэкранировав служебные знаки с помощью тильды или другого выбранного символа. Построитель корректно обработает такой текст запроса, сохранив возможность гибкой настройки остальных полей.
Таким образом, мы посмотрели два основных пути решения проблемы: простой и быстрый через квадратные скобки (подходит для большинства задач) и более сложный через ручное управление текстом запроса (для специфических требований к производительности или синтаксису).