При написании запросов к базе данных 1С разработчики нередко сталкиваются с необходимостью отфильтровать данные по текстовой маске или фрагменту строки с помощью оператора ПОДОБНО. Однако при составлении таких условий легко допустить как синтаксические, так и логические ошибки, а также создать узкие места в производительности системы. Разберем типичные ошибки, способы их исправления и оптимальные архитектурные практики.
Рассмотрим исходный фрагмент кода, в котором была сделана попытка исключить задачи, содержащие определенный текст:
ЗапросЗадачиЗаПериод.Текст = "
|ВЫБРАТЬ
| ЗадачаИсполнителя.Ссылка
|ИЗ
| Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
|ГДЕ
| ЗадачаИсполнителя.Наименование НЕ ПОДОБНО %[ПЕРЕНАПРАВЛЕННАЯ ЗАДАЧА]%
| ЗадачаИсполнителя.ДатаВыполненияПланово МЕЖДУ &НачДата И &КонДата
| ЗадачаИсполнителя.Исполнитель = &Исполнитель";
В данном фрагменте допущено сразу несколько базовых синтаксических ошибок:
""%Шаблон%"") либо передавать шаблон через параметр запроса.НЕ пишется перед всем выражением проверки условия: НЕ Поле ПОДОБНО &Шаблон, а не Поле НЕ ПОДОБНО.ГДЕ обязательно должны разделяться логическими операторами И или ИЛИ. Простой перенос строки не является разделителем условий в языке запросов.Проанализируем скрытую проблему, с которой сталкиваются при поиске подстрок, содержащих символы [ и ]. В языке запросов 1С квадратные скобки внутри шаблона ПОДОБНО являются служебными символами. Они задают перечисление диапазона символов (поиск любого одиночного символа из перечисленных внутри скобок).
Если написать шаблон "%[ПЕРЕНАПРАВЛЕННАЯ ЗАДАЧА]%", СУБД будет искать строки, в которых встречается хотя бы одна из букв (П, Е, Р, ...) или пробел, а не целую фразу в скобках. В результате условие отсечет практически все записи.
Для того чтобы квадратные скобки (а также символы % и _) воспринимались как обычные текстовые символы, необходимо применить ключевое слово СПЕЦСИМВОЛ и экранировать служебные знаки:
ЗапросЗадачиЗаПериод = Новый Запрос;
ЗапросЗадачиЗаПериод.Текст = "
|ВЫБРАТЬ
| ЗадачаИсполнителя.Ссылка КАК Ссылка
|ИЗ
| Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
|ГДЕ
| НЕ ЗадачаИсполнителя.Наименование ПОДОБНО &ШаблонПоиска СПЕЦСИМВОЛ ""/""
| И ЗадачаИсполнителя.ДатаВыполненияПланово МЕЖДУ &НачДата И &КонДата
| И ЗадачаИсполнителя.Исполнитель = &Исполнитель";
ЗапросЗадачиЗаПериод.УстановитьПараметр("НачДата", НачалоДня(ТекущаяДата()));
ЗапросЗадачиЗаПериод.УстановитьПараметр("КонДата", КонецДня(ТекущаяДата()));
ЗапросЗадачиЗаПериод.УстановитьПараметр("Исполнитель", ТекущийПользователь);
// Экранируем спецсимволы символом "/"
ЗапросЗадачиЗаПериод.УстановитьПараметр("ШаблонПоиска", "%/[ПЕРЕНАПРАВЛЕННАЯ ЗАДАЧА/]");
Посмотрим на правила использования экранирования:
/ или \.УстановитьПараметр() соответствует стандартам разработки 1С и исключает ошибки форматирования кавычек в тексте запроса.Выясним причину, почему использование оператора ПОДОБНО с маской %текст% считается нежелательным на больших объемах данных:
% стоит в начале шаблона, СУБД не может использовать индекс по полю Наименование. Это приводит к полному сканированию таблицы (Table Scan / Index Scan), что многократно замедляет выполнение запроса при росте количества записей.[...] поддерживаются не всеми СУБД (например, не поддерживаются в IBM DB2), а в PostgreSQL некорректно экранированные скобки могут приводить к ошибкам синтаксиса регулярных выражений на уровне базы данных.Попытка хранить признаки состояния объекта (например, признак перенаправления задачи) внутри текстового поля Наименование нарушает первую нормальную форму реляционных баз данных и приводит к необходимости написания неэффективных запросов.
Рассмотрим правильные варианты реализации задачи:
Задача.ЗадачаИсполнителя добавляется реквизит Перенаправлена с типом Булево. По данному реквизиту можно построить простой и быстрый отбор:
|ГДЕ
| НЕ ЗадачаИсполнителя.Перенаправлена
| И ЗадачаИсполнителя.ДатаВыполненияПланово МЕЖДУ &НачДата И &КонДата
| И ЗадачаИсполнителя.Исполнитель = &Исполнитель
НЕ В (...) без перебора текстовых полей.