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

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

При разработке алгоритмов поиска элементов справочников разработчики часто сталкиваются с ситуацией, когда запрос возвращает лишние позиции. Типичный пример: при попытке найти элемент с кратким наименованием «0» система находит позиции вида «0,00 конденсатор», «01 Резистор» и другие похожие строки. Разберем по шагам, почему так происходит, как работает оператор ПОДОБНО и в каких случаях следует использовать строгое равенство.

Анализ проблемы: почему оператор ПОДОБНО возвращает лишние данные

Рассмотрим исходный фрагмент кода, вызвавший неожиданное поведение:


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

Выясним причину такого результата. В языке запросов 1С оператор ПОДОБНО предназначен для сравнения строк по маске (шаблону). Символ процента % является специальным подстановочным знаком и обозначает любую последовательность символов произвольной длины (включая нулевую длину). Когда к переменной поиска добавляется процент в конце (Наименование + "%"), запрос ищет строки, которые начинаются с указанного значения. Соответственно, при значении «0» маска принимает вид 0%, под которую подпадают абсолютно любые наименования, начинающиеся с нуля.

Решение 1: Использование строгого равенства для точного поиска

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

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


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Ссылка
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	НЕ Номенклатура.ЭтоГруппа
|	И Номенклатура.Наименование = &ВыбНаим";

Запрос.УстановитьПараметр("ВыбНаим", Наименование);
Результат = Запрос.Выполнить().Выгрузить();

Разберем преимущества использования знака равенства:

  1. Корректность результата: в выборку попадут только те элементы, значение поля которых в точности равно переданному значению без посторонних суффиксов.
  2. Производительность СУБД: поле Наименование в справочниках 1С входит в стандартный индекс. Сравнение через знак равенства позволяет СУБД использовать поиск по индексу (Index Seek), что выполняется значительно быстрее, чем сканирование при использовании шаблонов.
  3. Обработка концевых пробелов: в большинстве поддерживаемых СУБД сравнение через = сопоставляет строки по правилам стандарта, при которых хвостовые пробелы могут автоматически компенсироваться, тогда как шаблонный поиск чувствителен к каждому знаку.

Решение 2: Шаблоны поиска с оператором ПОДОБНО

Если все же требуется искать элементы по частичному совпадению, проанализируем варианты правильного формирования шаблонов для оператора ПОДОБНО:

  1. Поиск строк, начинающихся с подстроки: маска вида &Наименование + "%". Например, при значении «Винт» найдутся «Винт М4», «Винтовой зажим».
  2. Поиск строк, заканчивающихся на подстроку: маска вида "%" + &Наименование. При значении «мм» найдутся «Кабель 10 мм», «Провод 2.5 мм».
  3. Поиск вхождения в любую часть строки: маска вида "%" + &Наименование + "%". Найдутся все записи, где искомая строка встречается в начале, середине или конце.

Посмотрим на пример кода с динамическим формированием условия поиска по вхождению:


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

Запрос.УстановитьПараметр("ШаблонПоиска", "%" + Наименование + "%");
Выборка = Запрос.Выполнить().Выбрать();

Важные нюансы работы со спецсимволами в операторе ПОДОБНО

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

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

Если в искомом наименовании содержится, например, символ подчеркивания («Товар_1»), оператор воспримет его как шаблон. Чтобы СУБД искала эти знаки как обычные символы текста, в запросе необходимо использовать конструкцию СПЕЦСИМВОЛ. Разберем пример экранирования:


// Экранируем символ процента и подчеркивания тильдой
ИскомыйТекст = СтрЗаменить(Наименование, "~", "~~");
ИскомыйТекст = СтрЗаменить(ИскомыйТекст, "%", "~%");
ИскомыйТекст = СтрЗаменить(ИскомыйТекст, "_", "~_");

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Ссылка
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	Номенклатура.Наименование ПОДОБНО &Маска СПЕЦСИМВОЛ ""~""";

Запрос.УстановитьПараметр("Маска", "%" + ИскомыйТекст + "%");

Альтернатива: поиск через менеджер справочника

Если поиск выполняется не в цикле и не требует объединения с другими таблицами базы, проанализируем штатный метод менеджера объекта:


СсылкаНаЭлемент = Справочники.Номенклатура.НайтиПоНаименованию(Наименование, Истина);
Если Не СсылкаНаЭлемент.Пустая() Тогда
	// Элемент успешно найден
КонецЕсли;

Обратим особое внимание на второй параметр метода НайтиПоНаименованию — ТочноеСоответствие. По умолчанию данный параметр равен Ложь. Если вызвать метод без второго параметра, платформа выполнит поиск именно по началу строки (аналогично ПОДОБНО &Наим + "%"). Для строгого совпадения передача флага Истина обязательна.

Очередность установки параметров и текста запроса

В тексте обсуждения возник вопрос: допустимо ли вызывать метод Запрос.УстановитьПараметр(...) до того, как задано свойство Запрос.Текст? Да, это полностью допустимо и не вызывает ошибок платформы 1С. Объект Запрос сохраняет параметры во внутренней коллекции. Синтаксический разбор текста, сопоставление переданных параметров и компиляция результирующего SQL-запроса происходят только в момент вызова метода Запрос.Выполнить(). Однако для читаемости и стандартизации программного кода рекомендуется сначала определять текст запроса, а затем заполнять его параметры.

← На главную