При работе со справочниками в платформе «1С:Предприятие» перед разработчиками часто возникает задача фильтрации или поиска элементов по специфическому текстовому шаблону. Например, требуется выбрать из базы данных всю номенклатуру, которая содержит пометку "(Брак)" строго в самом конце своего наименования. На первый взгляд задача кажется тривиальной, однако при её реализации в запросах существует множество тонкостей, связанных с производительностью СУБД, чувствительностью к регистру букв и кроссплатформенной совместимостью. Рассмотрим подробно, как решить эту задачу правильно, эффективно и с учетом современных стандартов разработки 1С.
Для фильтрации данных по текстовому шаблону на уровне СУБД в языке запросов 1С применяется оператор ПОДОБНО (аналог оператора LIKE в стандартном SQL). Этот оператор позволяет сравнивать строковое поле со специальным шаблоном, в котором можно использовать служебные спецсимволы.
Разберем основные спецсимволы, которые поддерживает оператор ПОДОБНО:
[а-я] или перечисление [абв]).Выясним причину частой ошибки начинающих разработчиков. Если мы напишем шаблон вида " % (Брак) % " (процент в начале и процент в конце), СУБД найдет все строки, где искомое словосочетание находится в любой части текста — в начале, в середине или в конце. Под это условие попадет, например, строка "Кабель (брак) синий". Чтобы отобрать элементы, у которых нужная нам подстрока находится строго в самом конце наименования, знак процента в конце шаблона ставить нельзя. Нам необходим шаблон вида "% (Брак)".
Проанализируем пример готового запроса для решения нашей задачи:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Наименование ПОДОБНО "%(Брак)"
В данном случае СУБД проанализирует поле Наименование и выберет только те элементы, которые заканчиваются на символы (Брак). Перед этой строкой может идти абсолютно любая последовательность символов произвольной длины.
В процессе обсуждения подобных задач часто возникает вопрос: нужно ли программно обрабатывать регистр букв? Например, искать отдельно "(Брак)", "(брак)" или "(БРАК)" с помощью оператора ИЛИ? Разберем этот нюанс подробнее.
Здесь важно разделять поведение системы при выполнении запроса в СУБД и при обработке строк во встроенном языке в оперативной памяти:
Cyrillic_General_CI_AS, где CI означает Case Insensitive — регистронезависимый). Благодаря этому оператор ПОДОБНО "%(Брак)" автоматически найдет элементы с окончаниями "(брак)", "(БРАК)" и даже "(БрАк)". Дополнительные конструкции с ИЛИ или шаблоны вида "%([Бб][Рр][Аа][Кк])" в запросах являются избыточными и лишь усложняют чтение кода и замедляют выполнение запроса.Если Текст = "значение" Тогда, система вернет ложь при несовпадении регистра букв. При работе с кодом в памяти обязательно приводите строки к одному регистру с помощью встроенных функций ВРег() или НРег():
// Пример проверки во встроенном языке 1С
Если Прав(НРег(СокрЛП(ВыборкаДетальныеЗаписи.Наименование)), 6) = "(брак)" Тогда
// Действие при совпадении условий
КонецЕсли;
Несмотря на то что запрос с шаблоном ПОДОБНО "%(Брак)" полностью решает функциональную задачу, у него есть серьезный скрытый недостаток, связанный с падением производительности информационной базы.
Рассмотрим по шагам, как СУБД выполняет данный запрос:
Наименование).ПОДОБНО "Брак%" поиск отработает мгновенно даже на миллионной таблице.ПОДОБНО "%(Брак)"), СУБД физически не может определить начальную точку поиска в индексе. В этом случае сервер базы данных вынужден прибегнуть к полному сканированию всей таблицы или всего индекса (Table Scan или Index Scan). СУБД будет вынуждена прочитать каждую строку таблицы и проверить её на соответствие шаблону.На высоконагруженных базах данных с миллионами записей в справочнике Номенклатура такой запрос вызовет критические задержки в работе пользователей и создаст избыточную нагрузку на дисковую подсистему и процессор сервера. Чтобы оптимизировать выполнение этой задачи, мы рекомендуем использовать следующие приемы:
Родитель), отбирайте только не помеченные на удаление элементы или делайте отбор по конкретному виду номенклатуры.В процессе оптимизации запросов или попыток обойти чувствительность к регистру разработчики иногда используют конструкции с квадратными скобками (например, ПОДОБНО "%[Бб][Рр][Аа][Кк]"). При написании таких запросов необходимо учитывать требования стандарта разработки 1С #std726, накладывающего ограничения на использование подобных конструкций на различных СУБД:
[...] и символ отрицания в них [^...], абсолютно не поддерживаются СУБД IBM DB2. Если ваше прикладное решение может эксплуатироваться на этой СУБД, использование данных символов в запросах приведет к аварийному завершению работы программы с ошибкой SQL.ГДЕ Наименование ПОДОБНО &ШаблонПоиска), СУБД PostgreSQL и Oracle воспримут квадратные скобки как обычные текстовые символы (то есть будут искать физическое присутствие символов скобок в наименовании), что приведет к неверным результатам выборки.Начиная с версии платформы 1С:Предприятие 8.3.23, разработчикам стал доступен штатный кроссплатформенный механизм работы с регулярными выражениями (Regex) непосредственно во встроенном языке. До этого для работы с регулярными выражениями приходилось использовать COM-объекты операционной системы Windows (например, VBScript.RegExp), что делало код несовместимым с серверами под управлением Linux.
Хотя регулярные выражения нельзя использовать непосредственно внутри текста запроса на уровне СУБД, они идеально подходят для постобработки полученных результатов, валидации вводимых пользователем данных при записи или разбора сложных текстовых файлов. Для этого используются новые встроенные функции, такие как СтрНайтиПоРегулярномуВыражению(), СтрЗаменитьПоРегулярномуВыражению(), а также логическая функция проверки соответствия СтрПодобно().
Рассмотрим пример использования регулярных выражений во встроенном языке для нашей задачи:
// Шаблон регулярного выражения:
// (?i) - включает регистронезависимый поиск
// \(брак\) - экранированные круглые скобки и слово "брак"
// $ - якорь конца строки, гарантирует поиск именно в конце наименования
ШаблонРегулярки = "(?i)\(брак\)$";
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
Если СтрПодобно(Выборка.Наименование, ШаблонРегулярки) Тогда
// Найдено точное совпадение в конце наименования независимо от регистра букв
Сообщить("Элемент с браком: " + Выборка.Наименование);
КонецЕсли;
КонецЦикла;
Этот способ обеспечивает максимальную гибкость и точность разбора текстовой информации без необходимости написания сложных алгоритмов ручного посимвольного анализа строк во встроенном языке 1С.