Как найти сразу несколько значений в табличной части справочника или документа в 1С?

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

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

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

Метод НайтиСтроки() является штатным инструментом для поиска в таблицах значений и табличных частях. Однако у него есть существенная особенность: в качестве параметра отбора он принимает Структура. Это накладывает два серьезных ограничения:

  1. Только строгое равенство: Мы можем искать строки, где значение колонки точно совпадает с переданным.
  2. Логическое "И": Если в структуру поиска добавить несколько полей, метод вернет только те строки, которые удовлетворяют всем условиям одновременно.

Рассмотрим ситуацию, когда нам нужно найти строки, где в колонке Номенклатура содержится любое значение из массива МассивТоваров. Передать массив напрямую в структуру поиска нельзя. Выясним, какие альтернативы существуют для решения этой задачи.

Решение №1: Использование запроса к временной таблице

Проанализируем самый мощный и гибкий способ — использование языка запросов. Этот метод позволяет реализовать условие В (&Массив), которое идеально подходит для поиска множества значений за один раз. Это особенно актуально, когда поиск выполняется на стороне сервера.

Разберем алгоритм по шагам:

  1. Выгрузим табличную часть в объект ТаблицаЗначений.
  2. Передадим эту таблицу в запрос в качестве параметра.
  3. В тексте запроса создадим временную таблицу из нашей ТЗ.
  4. Выполним выборку с условием ГДЕ Поле В (&МассивЗначений).

Пример программного кода для реализации этого метода:


// Допустим, у нас есть МассивНужныхЗначений и Объект.Товары (табличная часть)

// 1. Выгружаем ТЧ в таблицу значений
ТЗ_Товары = Объект.Товары.Выгрузить();

// 2. Создаем запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВременнаяТаблица.НомерСтроки,
    |   ВременнаяТаблица.Номенклатура,
    |   ВременнаяТаблица.Количество
    |ПОМЕСТИТЬ ВТ_Товары
    |ИЗ
    |   &ТЗ_Товары КАК ВременнаяТаблица
    |;
    |
    |ВЫБРАТЬ
    |   ВТ_Товары.НомерСтроки
    |ИЗ
    |   ВТ_Товары КАК ВТ_Товары
    |ГДЕ
    |   ВТ_Товары.Номенклатура В (&МассивНужныхЗначений)";

Запрос.УстановитьПараметр("ТЗ_Товары", ТЗ_Товары);
Запрос.УстановитьПараметр("МассивНужныхЗначений", МассивНужныхЗначений);

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

Пока Выборка.Следующий() Цикл
    // Работаем с найденными строками
    // Например, можно получить саму строку ТЧ по индексу (НомерСтроки - 1)
    СтрокаТЧ = Объект.Товары[Выборка.НомерСтроки - 1];
КонецЦикла;

Решение №2: Оптимизация поиска через индексацию

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

Посмотрим на пример того, как ускорить поиск с помощью индексов. Индексация создает хеш-таблицу в памяти, что позволяет находить нужные строки практически мгновенно.


// Сначала выгружаем в таблицу значений
ТаблицаПоиска = Объект.Товары.Выгрузить();

// ОБЯЗАТЕЛЬНО добавляем индекс по колонке, по которой будем искать
ТаблицаПоиска.Индексы.Добавить("Номенклатура");

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

Решение №3: Визуальный отбор в управляемых формах

Иногда под "поиском" подразумевается фильтрация строк на экране, чтобы пользователь увидел только те позиции, которые входят в массив. В управляемых формах для этого используется свойство ОтборСтрок элемента формы типа Таблица. Для настройки отборов и фильтрации зависимых строк на форме можно использовать решение для связывания табличных частей на управляемых формах.

Однако здесь мы сталкиваемся с тем же ограничением: ФиксированнаяСтруктура, используемая в ОтборСтрок, не поддерживает массивы. Чтобы обойти это ограничение, программисты часто используют один из следующих приемов:

Сравнение производительности и рекомендации

Проанализируем ситуацию: какой метод выбрать в зависимости от условий задачи?

  1. Малый объем данных (до 50-100 строк): Разница между запросом, индексацией и обычным циклом будет незаметна (миллисекунды). Здесь можно использовать простейший перебор для экономии времени разработки.
  2. Средний и большой объем данных: Однозначно рекомендуется использовать Запрос. Он выполняется на уровне оптимизированных механизмов платформы и позволяет за одно обращение получить весь результат.
  3. Частый поиск в одной и той же таблице: Если вам нужно постоянно обращаться к одной и той же коллекции в рамках одной процедуры, выгрузите её в ТаблицаЗначений и один раз постройте Индекс. Это обеспечит максимальную отзывчивость системы.

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

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

← На главную