Как найти строку в табличной части 1С по нескольким значениям (номенклатуре и характеристике)

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Разберем детально, как решить эту задачу эффективно, избежав распространенных ошибок вроде «Индекс находится за пределами массива», что часто встречается в приложениях для ТСД на Android.

Способ 1. Использование метода НайтиСтроки() со структурой

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

Рассмотрим пример кода для поиска строки по двум полям:


// Создаем структуру для поиска
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", ИскомаяНоменклатура);
Отбор.Вставить("Характеристика", ИскомаяХарактеристика);

// Выполняем поиск в табличной части "Товары"
МассивСтрок = Объект.Товары.НайтиСтроки(Отбор);

// Важно проверить, что массив не пустой, прежде чем обращаться к элементам
Если МассивСтрок.Количество() > 0 Тогда
    НайденнаяСтрока = МассивСтрок[0];
    // Теперь мы можем работать с НайденнаяСтрока напрямую
    НайденнаяСтрока.Количество = НайденнаяСтрока.Количество + 1;
Иначе
    Сообщить("Строка с указанными параметрами не найдена!");
КонецЕсли;

Важный нюанс: метод НайтиСтроки() всегда возвращает массив. Даже если найдена всего одна строка, это будет массив из одного элемента. Если соответствий нет, вернется пустой массив. Именно поэтому обращение к МассивСтрок[0] без предварительной проверки Количество() > 0 приведет к аварийному завершению программы.

Способ 2. Оптимизация поиска через индексацию (для больших таблиц)

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

Рассмотрим пошаговый алгоритм оптимизации:

  1. Выгружаем табличную часть в объект ТаблицаЗначений.
  2. Добавляем индекс по искомым колонкам.
  3. Выполняем поиск по индексированной таблице.

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

// 2. Создаем индекс для мгновенного поиска
ТЗ_Товары.Индексы.Добавить("Номенклатура, Характеристика");

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

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

Способ 3. Метод «Составного ключа» (для специфических задач)

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

Выясним причину популярности этого метода: он позволяет избежать работы с массивами. Реализуется это следующим образом:

  1. В табличную часть добавляется скрытая текстовая колонка, например, КлючСвязи.
  2. При заполнении или изменении строк в эту колонку записывается уникальная комбинация идентификаторов Номенклатуры и Характеристики.
  3. Поиск выполняется по этой одной колонке.

// Пример формирования ключа
КлючПоиска = Строка(Номенклатура.УникальныйИдентификатор()) + "_" + Строка(Характеристика.УникальныйИдентификатор());

// Поиск одной командой
НайденнаяСтрока = Объект.Товары.Найти(КлючПоиска, "КлючСвязи");

Если НайденнаяСтрока <> Неопределено Тогда
    // Строка найдена, работаем с ней
КонецЕсли;

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

Способ 4. Типизация данных — критический фактор поиска

Разберем одну из самых коварных ошибок: когда код написан верно, но НайтиСтроки() возвращает пустой результат. Часто проблема кроется в несоответствии типов.

Если в табличной части колонка Количество имеет тип Число, а вы передаете в структуру поиска Строку (например, полученную из текстового файла), поиск не даст результатов. Система 1С строго сравнивает типы данных.

Посмотрим на пример правильного приведения типов перед поиском:


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

Особенно это актуально для Характеристик. Если номенклатура ведется без характеристик, в табличной части будет стоять ПустаяСсылка, а не Неопределено или 0. Это важно учитывать при формировании структуры отбора.

Способ 5. Использование Построителя Запроса

Для обычных форм (что было упомянуто в обсуждении) существует еще один мощный метод — использование ПостроителяЗапроса. Это позволяет выполнять сложные отборы в табличных частях, используя мощь языка запросов к данным, находящимся непосредственно в памяти (в ТЧ).


Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(Объект.Товары);

// Добавляем условия отбора
НовыйОтбор = Построитель.Отбор.Добавить("Номенклатура");
НовыйОтбор.ВидСравнения = ВидСравнения.Равно;
НовыйОтбор.Значение = ИскомаяНоменклатура;
НовыйОтбор.Использование = Истина;

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

Этот метод избыточен для простого поиска по двум полям, но он незаменим, если вам нужно найти строки по условию «В списке», «Больше чем» или «Содержит».

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

← На главную