Как найти строки в таблице значений по частичному вхождению в 1С

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

При работе с объектом ТаблицаЗначений программисты часто сталкиваются с необходимостью найти данные не по полному совпадению, а по части строки. Например, когда в таблице хранится фамилия "Иванов", а поиск нужно выполнить по строке "Иван". Стандартные методы поиска в таблице имеют свои ограничения, которые мы подробно разберем в этой статье.

Ограничения стандартного метода НайтиСтроки

Рассмотрим стандартный подход, который первым приходит на ум — использование метода НайтиСтроки(). Этот метод принимает в качестве параметра структуру, где ключом является имя колонки, а значением — искомый текст. Однако важно понимать: метод НайтиСтроки() работает только по точному соответствию. Если вы передадите в отбор "Иван", а в таблице записано "Иванов", метод вернет пустой массив.

Проанализируем ситуацию: метод Найти() также не подходит для решения данной задачи, так как он возвращает только первую найденную строку и также требует полного совпадения значения. Для реализации поиска "по вхождению" нам необходимо использовать альтернативные механизмы платформы 1С.

Способ 1: Использование цикла и функции СтрНайти

Если ваша таблица значений содержит небольшое количество строк (до нескольких тысяч), самым простым и эффективным способом будет обычный перебор строк в цикле. Рассмотрим, как это реализовать с помощью функции СтрНайти(), которая появилась в платформе начиная с версии 8.3.10.

Разберем по шагам логику поиска в цикле:


// Предположим, ТЗ_Данные - наша таблица, а ТекстПоиска - подстрока "Иван"
НайденныеСтроки = Новый Массив;

Для Каждого СтрокаТЗ Из ТЗ_Данные Цикл
    // Используем СтрНайти для поиска подстроки в колонке "Наименование"
    // Функция возвращает позицию первого знака или 0, если не найдено
    Если СтрНайти(СтрокаТЗ.Наименование, ТекстПоиска) > 0 Тогда
        НайденныеСтроки.Добавить(СтрокаТЗ);
    КонецЕсли;
КонецЦикла;

// Проверим результат
Если НайденныеСтроки.Количество() > 0 Тогда
    Сообщить("Найдено совпадений: " + НайденныеСтроки.Количество());
КонецЕсли;

Преимущество этого метода в том, что он не требует сложной подготовки таблицы и работает максимально прозрачно. Если вы используете более старую версию платформы, вместо СтрНайти() можно применить функцию Найти(), которая работает аналогично.

Способ 2: Поиск через запрос (использование временных таблиц)

Для работы с большими объемами данных или в случаях, когда нужно объединить поиск с другими условиями, эффективнее использовать механизм запросов. В языке запросов 1С существует оператор ПОДОБНО, который идеально подходит для поиска по маске.

Однако просто передать таблицу значений в запрос нельзя. Выясним причину: чтобы 1С могла обработать таблицу значений как источник данных для запроса, она должна быть помещена во временную таблицу. И здесь кроется главная техническая тонкость — колонки таблицы должны иметь строго определенные типы. Для расширения возможностей работы с такими объектами можно ознакомиться с разбором особенностей добавления данных во временную таблицу.

Важность типизации колонок таблицы значений

Если вы создаете таблицу значений просто методом ТЗ.Колонки.Добавить("Наименование"), то тип этой колонки будет "Произвольный". При попытке передать такую таблицу в запрос вы получите ошибку: "Тип не может быть выбран в запросе". Чтобы этого избежать, при создании таблицы необходимо явно описывать типы данных.

Рассмотрим пример правильной подготовки таблицы значений для запроса:


// Создаем описание типа для строки заданной длины
КвалификаторыСтроки = Новый КвалификаторыСтроки(150);
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка", , КвалификаторыСтроки);

ТЗ_AxСпецификаций = Новый ТаблицаЗначений;
// Добавляем типизированные колонки
ТЗ_AxСпецификаций.Колонки.Добавить("AxCode_Комплектующее", ОписаниеТипаСтрока);
ТЗ_AxСпецификаций.Колонки.Добавить("Наименование_Комплектующее", ОписаниеТипаСтрока);

// Заполнение таблицы данными (пример)
НоваяСтрока = ТЗ_AxСпецификаций.Добавить();
НоваяСтрока.AxCode_Комплектующее = "001";
НоваяСтрока.Наименование_Комплектующее = "Иванов Иван Иванович";

Обратите внимание: если ваша таблица значений является результатом выполнения другого запроса (получена методом Выгрузить()), то она уже содержит типизированные колонки, и дополнительно описывать их не нужно.

Реализация запроса с оператором ПОДОБНО

Теперь, когда наша таблица типизирована, мы можем составить запрос для поиска. Мы объединим помещение во временную таблицу и выборку с условием в одном пакете запросов.


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

// Формируем текст поиска с использованием спецсимвола "%"
// % - означает любое количество любых символов
Запрос.УстановитьПараметр("ТекстПоиска", "%" + Объект.СтрокаПоиска + "%");
Запрос.УстановитьПараметр("ТЗ_Источник", ТЗ_AxСпецификаций);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    Сообщить("Найден код: " + Выборка.Код);
КонецЦикла;

Тонкости использования оператора ПОДОБНО

Проанализируем работу оператора ПОДОБНО подробнее. Он позволяет использовать специальные символы маски:

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

Посмотрим на примеры:

Регистрозависимость и производительность

Выясним, как регистр букв влияет на результат. В запросах 1С чувствительность к регистру часто зависит от настроек используемой СУБД (SQL Server, PostgreSQL). Чтобы поиск гарантированно не зависел от того, написали вы "иван" или "Иван", рекомендуется приводить обе части сравнения к верхнему регистру с помощью функции ВРЕГ. Для изучения более сложных ситуаций и предотвращения ошибок можно ознакомиться с материалом о нюансах сравнения строковых полей в запросах.


// В тексте запроса
ГДЕ ВРЕГ(ВТ_Данные.Наименование) ПОДОБНО ВРЕГ(&ТекстПоиска)

Что касается производительности, помните: поиск в цикле через СтрНайти работает быстрее на малых объемах, так как не тратится время на передачу таблицы в менеджер временных таблиц и обратно. Запрос становится выгодным при необходимости сложной фильтрации или работе с ТЗ объемом более 10-20 тысяч строк.

Подводя итог, мы разобрали, что для быстрого решения задачи по частичному поиску в ТаблицаЗначений лучше использовать цикл с функцией СтрНайти, а для более масштабных задач — запросы через временные таблицы с обязательной предварительной типизацией колонок.

← На главную