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