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