К статье
Практический материал

Разработка и Конфигурация · 12 мин

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

Способы поиска строк в табличной части документа 1С: методы Найти, НайтиСтроки, перебор в цикле, поиск в форме. Примеры кода, ошибки и проверка результата.

Табличная часть документа в 1С — это коллекция строк, и почти любая доработка рано или поздно сводится к задаче: найти строку с нужной номенклатурой, проверить, есть ли дубли, или получить все строки с определённым складом. Платформа даёт для этого несколько инструментов, и выбор между ними влияет и на скорость кода, и на его читаемость.

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

Ниже разобраны все рабочие варианты с примерами кода, типичными ошибками и способами проверить, что поиск действительно нашёл то, что нужно.

Что такое табличная часть и как к ней обратиться

Табличная часть — это коллекция строк, подчинённая объекту: документу, справочнику или обработке. У документа «Реализация товаров и услуг» это, например, табличные части «Товары» и «Услуги». Каждая строка — объект со своим набором реквизитов: номенклатура, количество, цена, сумма и так далее.

Обращение к табличной части зависит от контекста. В модуле объекта или в обработке, работающей с объектом документа, пишут Объект.Товары или ДокументОбъект.Товары. В модуле формы управляемого приложения данные лежат в реквизите формы: Объект.Товары — это данные формы коллекция, у которой методы поиска немного отличаются. Эта разница — частый источник ошибок, к ней вернёмся ниже.

Количество строк можно получить через Объект.Товары.Количество(), а обратиться к конкретной строке — по индексу: Объект.Товары[0] (нумерация с нуля). Поиск нужен тогда, когда индекс заранее неизвестен.

Метод Найти() — поиск одной строки по точному значению

Метод Найти(Значение, ИмяКолонки) возвращает первую строку, где указанный реквизит равен искомому значению. Если ничего не найдено, метод возвращает Неопределено — это обязательно нужно проверять, иначе при обращении к реквизиту результата получите ошибку «Поле объекта не обнаружено».

СтрокаТовара = Объект.Товары.Найти(НоменклатураИскомая, "Номенклатура");

Если СтрокаТовара = Неопределено Тогда

Сообщить("Товар в табличной части не найден");

Иначе

СтрокаТовара.Количество = СтрокаТовара.Количество + 1;

КонецЕсли;

Второй параметр — имя колонки строкой — указывать не обязательно, но без него поиск пойдёт по всем колонкам, что медленнее и может дать неожиданный результат, если искомое значение встречается в другом реквизите. Всегда указывайте колонку явно.

Важное ограничение: Найти() сравнивает на строгое равенство. Поиск «по части наименования», «больше суммы» или «с учётом нескольких условий» этим методом не решается — для этого есть другие инструменты.

Метод НайтиСтроки() — выборка нескольких строк по отбору

Когда нужны все строки, удовлетворяющие условию, используйте НайтиСтроки(ПараметрыОтбора). Отбор задаётся структурой, где ключ — имя реквизита, значение — искомое значение. Условия внутри структуры объединяются по «И».

Отбор = Новый Структура;

Отбор.Вставить("Склад", СкладОтгрузки);

Отбор.Вставить("СтавкаНДС", Перечисления.СтавкиНДС.НДС20);

НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Для Каждого СтрокаТовара Из НайденныеСтроки Цикл

СтрокаТовара.Сумма = СтрокаТовара.Количество * СтрокаТовара.Цена;

КонецЦикла;

Метод возвращает массив строк. Если совпадений нет, массив будет пустым — проверяйте НайденныеСтроки.Количество() = 0 перед обработкой. Сам массив — копия ссылок на строки: изменения строк через него отражаются в табличной части, но удаление элемента из массива строку из табличной части не удаляет.

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

Порядок действий при поиске по отбору
  1. 1
    Сформируйте структуру отбора: ключ — имя реквизита табличной части, значение — искомое значение
  2. 2
    Вызовите НайтиСтроки(Отбор) и сохраните результат в переменную
  3. 3
    Проверьте количество найденных строк через Количество()
  4. 4
    Обработайте строки в цикле Для Каждого
  5. 5
    Если строка одна — используйте Найти() и проверьте результат на Неопределено

Перебор в цикле — когда условие сложнее равенства

Цикл Для Каждого — универсальный способ, когда нужно сравнение «больше/меньше», поиск подстроки в наименовании, проверка по функции или комбинация условий с «ИЛИ».

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Если СтрокаТовара.Сумма > 100000

Или СтрНайти(СтрокаТовара.Номенклатура.Наименование, "услуга") > 0 Тогда

// действия со строкой

КонецЕсли;

КонецЦикла;

Для поиска по индексу есть классический цикл: Для Индекс = 0 По Объект.Товары.Количество() - 1 Цикл. Он нужен, когда внутри цикла вы удаляете строки — удалять элементы коллекции внутри Для Каждого нельзя, это приводит к пропуску строк или ошибке. При удалении перебирайте коллекцию с конца или сначала соберите строки для удаления через НайтиСтроки(), а потом удаляйте их методом Удалить(Строка).

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

Поиск в форме документа без программирования

Пользователю, который просто хочет найти товар в длинном документе, код не нужен. В управляемых формах работают стандартные инструменты таблицы: установите курсор в табличную часть и нажмите Ctrl+F — откроется диалог поиска по текущей колонке. Кнопки «Найти следующее» / «Найти предыдущее» доступны и в меню «Ещё» таблицы.

Дополнительно в большинстве типовых конфигураций у табличных частей есть команда «Найти…» в меню «Ещё», а также возможность сортировки по колонке и отбора. Если документ большой, сортировка по номенклатуре часто быстрее приводит к нужной строке, чем последовательный поиск.

В толстом клиенте и обычных формах поиск по табличному полю вызывается аналогично — Ctrl+F или через контекстное меню таблицы. Учтите, что поиск ищет по отображаемому представлению колонки, поэтому искать номенклатуру нужно по наименованию, а не по коду, если колонка кода скрыта.

Поиск в данных формы: отличия управляемого приложения

В модуле управляемой формы Объект.Товары — это не таблица значений, а ДанныеФормыКоллекция. Методы Найти() у неё нет — вместо него используется НайтиСтроки(Отбор), который работает так же, как у таблицы значений, и возвращает массив строк.

&НаКлиенте

Процедура НайтиТовар(Команда)

Отбор = Новый Структура("Номенклатура", ТекущаяНоменклатура);

Строки = Объект.Товары.НайтиСтроки(Отбор);

Если Строки.Количество() > 0 Тогда

Элементы.Товары.ТекущаяСтрока = Строки[0].ПолучитьИдентификатор();

КонецЕсли;

КонецПроцедуры

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

Типичные ошибки
01
Использование Найти() в модуле управляемой формы — у ДанныеФормыКоллекция этого метода нет, возникнет ошибка; используйте НайтиСтроки()
02
Отсутствие проверки результата Найти() на Неопределено — обращение к реквизиту результата прерывает выполнение
03
Поиск по строковому представлению ссылки вместо самой ссылки — Найти("Молоко", "Номенклатура") не найдёт строку, нужно передавать ссылку на элемент справочника
04
Удаление строк внутри цикла Для Каждого — коллекция изменяется во время перебора, строки пропускаются
05
Присваивание ТекущаяСтрока индекса вместо идентификатора строки в управляемой форме — позиционирование не срабатывает

Выбор метода под задачу

Краткая логика выбора: одна строка по точному равенству — Найти(); несколько строк по одному или нескольким равенствам — НайтиСтроки(); условие со сравнением, подстрокой или «ИЛИ» — цикл; пользовательская задача в форме — Ctrl+F. Для массовых обработок, где табличные части читаются из множества документов, эффективнее запрос с обращением к табличной части через точку: РеализацияТоваровУслуг.Товары как источник данных.

Сравнение вариантов

Найти()

Одна строка по точному равенству реквизита. Не работает в ДанныеФормыКоллекция управляемой формы

НайтиСтроки()

Массив строк по структуре отбора с условиями по И. Универсален: работает и с объектом, и с данными формы

Цикл Для Каждого

Любые условия: сравнения, подстроки, функции. Чуть больше кода, удалять строки внутри нельзя

Запрос к табличной части

Поиск по множеству документов сразу, группировки и итоги. Только чтение, изменять объект нужно отдельно

Ctrl+F в форме

Интерактивный поиск пользователем без кода. Ищет по отображаемому значению одной колонки

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

Контрольные точки

Как проверить результат

Документ с известной строкой
Норма

Найти()/НайтиСтроки() возвращает именно эту строку, реквизиты совпадают

Тревожный признак

Возвращается Неопределено или другая строка — проверьте тип и значение отбора

Документ без совпадений
Норма

Найти() вернул Неопределено, НайтиСтроки() — пустой массив, ошибок нет

Тревожный признак

Ошибка выполнения — значит, нет проверки результата

Документ с дублями
Норма

НайтиСтроки() возвращает все строки-дубли

Тревожный признак

Найдена только первая — возможно, использован Найти() вместо НайтиСтроки()

Позиционирование в форме
Норма

Курсор таблицы встаёт на найденную строку

Тревожный признак

Таблица не двигается — проверьте ПолучитьИдентификатор()

Частые вопросы

Как найти строку по двум реквизитам одновременно?

Используйте НайтиСтроки() со структурой из двух элементов: Отбор.Вставить("Номенклатура", Товар); Отбор.Вставить("Склад", Склад). Условия объединяются по «И». Если нужна только первая строка, возьмите нулевой элемент полученного массива после проверки его длины.

Как найти строку по части наименования товара?

Методы Найти() и НайтиСтроки() работают только на точное равенство, поэтому нужен перебор в цикле с функцией СтрНайти(): если СтрНайти(СтрокаТовара.Номенклатура.Наименование, Фрагмент) > 0 — строка подходит. Учтите, что обращение к наименованию через точку вызывает обращение к данным ссылки.

Почему Найти() не находит строку, хотя товар в табличной части есть?

Чаще всего причина в несовпадении типов: в отбор передана строка с наименованием или кодом, а реквизит хранит ссылку на справочник. Передавайте в Найти() именно ссылку на элемент. Также проверьте, что в значении нет лишних пробелов и что поиск идёт по той табличной части (например, «Товары», а не «Услуги»).

Как удалить все найденные строки?

Сначала получите массив через НайтиСтроки(Отбор), затем в цикле по массиву вызовите Объект.Товары.Удалить(СтрокаМассива). Удалять строки прямо внутри перебора самой табличной части нельзя — коллекция изменится во время итерации.

Как узнать номер найденной строки?

У строки табличной части есть свойство НомерСтроки (нумерация с единицы). Также индекс можно получить методом Объект.Товары.Индекс(НайденнаяСтрока) — он возвращает позицию с нуля. В управляемой форме для позиционирования используйте ПолучитьИдентификатор(), а не номер строки.

Чем поиск в табличной части отличается от поиска запросом?

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

Итог

Что важно запомнить

Точное равенство и одна строка — Найти() с обязательной проверкой на Неопределено; выборка по отбору — НайтиСтроки() со структурой; сложные условия — цикл Для Каждого. В управляемой форме доступен только НайтиСтроки(), а позиционирование выполняется через ПолучитьИдентификатор(). Пользователю без кода достаточно Ctrl+F в таблице документа.