В практике разработчика 1С часто возникает задача сопоставления "грязных" или неструктурированных данных (например, загруженных из Excel) с существующими справочниками системы. Типичный пример: в строке указано «Компьютер Acer 5232», и программу нужно «научить» автоматически определять, что этот элемент относится к группе «Компьютеры» или «Системные блоки». Рассмотрим подробнее, как эффективно реализовать такой поиск с помощью механизмов платформы 1С.
Основным инструментом для поиска подстроки в языке запросов 1С является оператор ПОДОБНО. Он позволяет сравнивать строковое поле с шаблоном, где используются специальные символы маски:
Проанализируем ситуацию, когда нам нужно найти все наименования, содержащие слово «Компьютер». В коде запроса это будет выглядеть следующим образом:
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО ""%Компьютер%""";
Важно помнить, что использование процента в начале шаблона (%Текст) лишает СУБД возможности использовать индексы, что может привести к замедлению работы на больших таблицах. Если бизнес-логика позволяет искать только по началу строки, лучше использовать шаблон Текст%.
Когда данные для поиска находятся не в базе, а во внешней таблице (например, в ТаблицаЗначений), разберем по шагам правильный алгоритм действий. Нельзя просто перебирать таблицу в цикле и выполнять запрос на каждой итерации — это крайне неэффективно. Правильный путь — передать всю таблицу в запрос и выполнить соединение на уровне базы данных.
Выясним причину, по которой новички часто совершают ошибки на этом этапе. Для корректной работы со строками неограниченной длины или длинными строками в ТаблицаЗначений их необходимо приводить к фиксированной длине с помощью функции ПОДСТРОКА. Рассмотрим пример подготовки и передачи таблицы в запрос:
// Подготовим таблицу значений с данными из Excel
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(200)));
// Заполним таблицу...
// ...
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Шаг 1: Помещаем ТЗ во временную таблицу
Запрос.Текст =
"ВЫБРАТЬ
| ПОДСТРОКА(ТЗ.Наименование, 1, 200) КАК НаименованиеДляПоиска
|ПОМЕСТИТЬ ВТ_ДанныеExcel
|ИЗ
| &ТЗ КАК ТЗ";
Запрос.УстановитьПараметр("ТЗ", ТЗ);
Запрос.Выполнить();
Теперь посмотрим на пример финального запроса, который сопоставит наши данные из временной таблицы со справочником категорий. Обратите внимание на конструкцию соединения — мы будем использовать условие ПОДОБНО непосредственно в секции ПО.
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст =
"ВЫБРАТЬ
| ВТ.НаименованиеДляПоиска КАК ИсходнаяСтрока,
| Группы.Ссылка КАК НайденнаяГруппа
|ИЗ
| ВТ_ДанныеExcel КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КатегорииТоваров КАК Группы
| ПО (ВТ.НаименованиеДляПоиска ПОДОБНО ""%"" + Группы.Наименование + ""%"")";
Результат = Запрос2.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
// Здесь мы получаем результат сопоставления
// Если НайденнаяГруппа = NULL, значит вхождение не найдено
КонецЦикла;
Проанализируем ситуацию с "размножением" строк (кросс-соединение). Если в исходной строке «Компьютер и Принтер» встретятся ключевые слова сразу из двух групп («Компьютеры» и «Принтеры»), запрос вернет две записи для одной исходной строки. Чтобы этого избежать, рассмотрим подробнее использование группировки:
Запрос.Текст =
"ВЫБРАТЬ
| ВТ.НаименованиеДляПоиска КАК ИсходнаяСтрока,
| МИНИМУМ(Группы.Ссылка) КАК НайденнаяГруппа
|ИЗ
| ВТ_ДанныеExcel КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КатегорииТоваров КАК Группы
| ПО (ВТ.НаименованиеДляПоиска ПОДОБНО ""%"" + Группы.Наименование + ""%"")
|СГРУППИРОВАТЬ ПО
| ВТ.НаименованиеДляПоиска";
Начиная с версии платформы 8.3.20, функция СТРНАЙТИ стала доступна непосредственно в тексте запроса. Это делает код более читаемым и иногда более производительным. Посмотрим на пример использования этой функции:
|ВЫБРАТЬ
| Таблица.Наименование
|ИЗ
| Таблица КАК Таблица
|ГДЕ
| СТРНАЙТИ(Таблица.Наименование, ""Компьютер"") > 0
Если же ваша задача подразумевает поиск по огромным массивам данных (миллионы записей) с учетом морфологии (склонений слов), рекомендуем использовать механизм Полнотекстового поиска. Он работает через специальные индексы и позволяет находить данные мгновенно, используя объект ПолнотекстовыйПоиск.
При использовании ПОДОБНО важно учитывать, что в самих наименованиях товаров могут содержаться символы, которые язык запросов интерпретирует как служебные (например, "%" в названии "Спирт 95%"). В таких случаях необходимо использовать ключевое слово СПЕЦСИМВОЛ. Рассмотрим подробнее:
// Если мы ищем строку, содержащую символ "%"
// Используем "/" как экранирующий символ
Запрос.Текст = "ГДЕ Номенклатура.Наименование ПОДОБНО ""%95/%"" СПЕЦСИМВОЛ ""/""";
Подведем итог: поиск по вхождению в строке — это мощный инструмент для автоматизации сопоставления данных. Комбинируя временные таблицы, оператор ПОДОБНО и правильные типы соединений, можно значительно ускорить процесс обработки входящей информации и минимизировать ручной труд пользователя.