Как получить и обработать все строки табличной части документа при наличии дублирующихся значений?

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

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

В этой статье мы подробно разберем, как правильно извлекать все подходящие строки ТЧ, как их редактировать и как оптимизировать этот процесс для работы с большими объемами данных. Мы рассмотрим несколько подходов: от простого использования встроенных методов до высокопроизводительных запросов.

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

Самый простой и логичный способ получить массив всех строк, удовлетворяющих условию, — это использование метода НайтиСтроки(). В отличие от своего «собрата», этот метод возвращает не одну строку, а Массив объектов строк табличной части.

Рассмотрим ситуацию, когда у нас есть массив лицевых счетов, и нам нужно найти все соответствующие строки в табличной части документа, чтобы изменить в них значение колонки ДокументОплаты. Проанализируем алгоритм действий:

  1. Создаем структуру отбора, где ключом будет имя колонки ТЧ, а значением — искомый объект.
  2. Вызываем метод НайтиСтроки(СтруктураОтбора).
  3. Обходим полученный массив циклом и вносим необходимые изменения.

Посмотрим на практический пример кода:


// Допустим, ЛицевыеСчета — это табличная часть нашего документа
// МассивЛС — массив ссылок на справочник ЛицевыеСчета

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

Важный технический нюанс: метод НайтиСтроки() возвращает ссылки на объекты строк, находящиеся в оперативной памяти. Это означает, что любое изменение реквизита внутри цикла Для каждого СтрокаТЧ Из НайденныеСтроки напрямую меняет данные в самой табличной части документа. Вам не нужно «записывать» строку обратно в таблицу.

Метод 2: Оптимизация производительности через «Соответствие» (Map)

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

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

Рассмотрим пошагово этот эффективный метод:

  1. Помещаем все элементы искомого массива в объект Соответствие. Поиск по ключу в соответствии работает практически мгновенно.
  2. Запускаем один единственный цикл по всей табличной части документа.
  3. Для каждой строки проверяем, есть ли её значение в нашем соответствии.

// Подготовим соответствие для быстрого поиска
БыстрыйПоискЛС = Новый Соответствие;
Для Каждого Элемент Из МассивЛС Цикл
    БыстрыйПоискЛС.Вставить(Элемент, Истина);
КонецЦикла;

// Один проход по табличной части
Для Каждого СтрокаТЧ Из Объект.ЛицевыеСчета Цикл
    
    // Если лицевой счет из строки есть в нашем списке
    Если БыстрыйПоискЛС[СтрокаТЧ.ЛицевойСчет] <> Неопределено Тогда
        СтрокаТЧ.ДокументОплаты = СсылкаНаДокумент;
    КонецЕсли;
    
КонецЦикла;

Этот подход работает значительно быстрее, так как мы читаем таблицу всего один раз, независимо от того, сколько лицевых счетов мы ищем.

Метод 3: Использование запросов для работы с ТЧ

Проанализируем ситуацию, когда данных очень много или нам требуется сложная логика отбора (например, по нескольким условиям или со связями из других таблиц). В этом случае наиболее правильным и «каноничным» методом будет использование запроса.

Многие начинающие разработчики задаются вопросом: изменятся ли данные в ТЧ, если мы выберем их запросом? Ответ: напрямую — нет. Запрос возвращает копию данных из базы или из переданной таблицы. Однако мы можем получить индексы строк или уникальные идентификаторы, чтобы затем обратиться к объекту.

Если документ уже записан в базу данных, мы можем обратиться к его табличной части через запрос к метаданным:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ДокТЧ.НомерСтроки - 1 КАК Индекс
    |ИЗ
    |   Документ.НачислениеЗарплаты.ЛицевыеСчета КАК ДокТЧ
    |ГДЕ
    |   ДокТЧ.Ссылка = &Ссылка
    |   И ДокТЧ.ЛицевойСчет В (&МассивЛС)";

Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
Запрос.УстановитьПараметр("МассивЛС", МассивЛС);

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

Пока Результат.Следующий() Цикл
    // Обращаемся к строке по индексу и меняем её
    СтрокаТЧ = Объект.ЛицевыеСчета[Результат.Индекс];
    СтрокаТЧ.ДокументОплаты = СсылкаНаДокумент;
КонецЦикла;

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

Типичные ошибки при поиске строк

Разберем основные ошибки, которые могут возникнуть при реализации подобных задач:

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

← На главную