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