Разработка и Конфигурация · 12 мин
Как найти строку в табличной части документа 1С
Способы поиска строк в табличной части документа 1С: методы Найти, НайтиСтроки, перебор в цикле, поиск в форме. Примеры кода, ошибки и проверка результата.
Табличная часть документа в 1С — это коллекция строк, и почти любая доработка рано или поздно сводится к задаче: найти строку с нужной номенклатурой, проверить, есть ли дубли, или получить все строки с определённым складом. Платформа даёт для этого несколько инструментов, и выбор между ними влияет и на скорость кода, и на его читаемость.
Основные способы — методы Найти() и НайтиСтроки(), перебор коллекции в цикле, а также интерактивный поиск в форме документа, который доступен пользователю без программирования. У каждого подхода есть свои условия применения: где-то важна скорость, где-то — гибкость условия, а где-то задача вообще решается без кода.
Ниже разобраны все рабочие варианты с примерами кода, типичными ошибками и способами проверить, что поиск действительно нашёл то, что нужно.
Что такое табличная часть и как к ней обратиться
Табличная часть — это коллекция строк, подчинённая объекту: документу, справочнику или обработке. У документа «Реализация товаров и услуг» это, например, табличные части «Товары» и «Услуги». Каждая строка — объект со своим набором реквизитов: номенклатура, количество, цена, сумма и так далее.
Обращение к табличной части зависит от контекста. В модуле объекта или в обработке, работающей с объектом документа, пишут Объект.Товары или ДокументОбъект.Товары. В модуле формы управляемого приложения данные лежат в реквизите формы: Объект.Товары — это данные формы коллекция, у которой методы поиска немного отличаются. Эта разница — частый источник ошибок, к ней вернёмся ниже.
Количество строк можно получить через Объект.Товары.Количество(), а обратиться к конкретной строке — по индексу: Объект.Товары[0] (нумерация с нуля). Поиск нужен тогда, когда индекс заранее неизвестен.
Метод Найти() — поиск одной строки по точному значению
Метод Найти(Значение, ИмяКолонки) возвращает первую строку, где указанный реквизит равен искомому значению. Если ничего не найдено, метод возвращает Неопределено — это обязательно нужно проверять, иначе при обращении к реквизиту результата получите ошибку «Поле объекта не обнаружено».
СтрокаТовара = Объект.Товары.Найти(НоменклатураИскомая, "Номенклатура");
Если СтрокаТовара = Неопределено Тогда
Сообщить("Товар в табличной части не найден");
Иначе
СтрокаТовара.Количество = СтрокаТовара.Количество + 1;
КонецЕсли;
Второй параметр — имя колонки строкой — указывать не обязательно, но без него поиск пойдёт по всем колонкам, что медленнее и может дать неожиданный результат, если искомое значение встречается в другом реквизите. Всегда указывайте колонку явно.
Важное ограничение: Найти() сравнивает на строгое равенство. Поиск «по части наименования», «больше суммы» или «с учётом нескольких условий» этим методом не решается — для этого есть другие инструменты.
Метод НайтиСтроки() — выборка нескольких строк по отбору
Когда нужны все строки, удовлетворяющие условию, используйте НайтиСтроки(ПараметрыОтбора). Отбор задаётся структурой, где ключ — имя реквизита, значение — искомое значение. Условия внутри структуры объединяются по «И».
Отбор = Новый Структура;
Отбор.Вставить("Склад", СкладОтгрузки);
Отбор.Вставить("СтавкаНДС", Перечисления.СтавкиНДС.НДС20);
НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);
Для Каждого СтрокаТовара Из НайденныеСтроки Цикл
СтрокаТовара.Сумма = СтрокаТовара.Количество * СтрокаТовара.Цена;
КонецЦикла;
Метод возвращает массив строк. Если совпадений нет, массив будет пустым — проверяйте НайденныеСтроки.Количество() = 0 перед обработкой. Сам массив — копия ссылок на строки: изменения строк через него отражаются в табличной части, но удаление элемента из массива строку из табличной части не удаляет.
Типичный сценарий — поиск дублей. Для каждой строки проверяют, сколько строк с такой же номенклатурой есть в табличной части, и если больше одной — объединяют или сообщают пользователю.
- 1Сформируйте структуру отбора: ключ — имя реквизита табличной части, значение — искомое значение
- 2Вызовите НайтиСтроки(Отбор) и сохраните результат в переменную
- 3Проверьте количество найденных строк через Количество()
- 4Обработайте строки в цикле Для Каждого
- 5Если строка одна — используйте Найти() и проверьте результат на Неопределено
Перебор в цикле — когда условие сложнее равенства
Цикл Для Каждого — универсальный способ, когда нужно сравнение «больше/меньше», поиск подстроки в наименовании, проверка по функции или комбинация условий с «ИЛИ».
Для Каждого СтрокаТовара Из Объект.Товары Цикл
Если СтрокаТовара.Сумма > 100000
Или СтрНайти(СтрокаТовара.Номенклатура.Наименование, "услуга") > 0 Тогда
// действия со строкой
КонецЕсли;
КонецЦикла;
Для поиска по индексу есть классический цикл: Для Индекс = 0 По Объект.Товары.Количество() - 1 Цикл. Он нужен, когда внутри цикла вы удаляете строки — удалять элементы коллекции внутри Для Каждого нельзя, это приводит к пропуску строк или ошибке. При удалении перебирайте коллекцию с конца или сначала соберите строки для удаления через НайтиСтроки(), а потом удаляйте их методом Удалить(Строка).
По производительности перебор в цикле сопоставим с НайтиСтроки() на типовых объёмах документов (десятки и сотни строк). Разница становится заметной только на очень больших табличных частях — там выигрывает встроенный метод.
Поиск в форме документа без программирования
Пользователю, который просто хочет найти товар в длинном документе, код не нужен. В управляемых формах работают стандартные инструменты таблицы: установите курсор в табличную часть и нажмите Ctrl+F — откроется диалог поиска по текущей колонке. Кнопки «Найти следующее» / «Найти предыдущее» доступны и в меню «Ещё» таблицы.
Дополнительно в большинстве типовых конфигураций у табличных частей есть команда «Найти…» в меню «Ещё», а также возможность сортировки по колонке и отбора. Если документ большой, сортировка по номенклатуре часто быстрее приводит к нужной строке, чем последовательный поиск.
В толстом клиенте и обычных формах поиск по табличному полю вызывается аналогично — Ctrl+F или через контекстное меню таблицы. Учтите, что поиск ищет по отображаемому представлению колонки, поэтому искать номенклатуру нужно по наименованию, а не по коду, если колонка кода скрыта.
Поиск в данных формы: отличия управляемого приложения
В модуле управляемой формы Объект.Товары — это не таблица значений, а ДанныеФормыКоллекция. Методы Найти() у неё нет — вместо него используется НайтиСтроки(Отбор), который работает так же, как у таблицы значений, и возвращает массив строк.
&НаКлиенте
Процедура НайтиТовар(Команда)
Отбор = Новый Структура("Номенклатура", ТекущаяНоменклатура);
Строки = Объект.Товары.НайтиСтроки(Отбор);
Если Строки.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Строки[0].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Чтобы визуально спозиционировать таблицу формы на найденной строке, присвойте свойству ТекущаяСтрока элемента формы идентификатор строки, полученный методом ПолучитьИдентификатор(). Прямое присваивание индекса не сработает — данные формы адресуются по идентификаторам.
Выбор метода под задачу
Краткая логика выбора: одна строка по точному равенству — Найти(); несколько строк по одному или нескольким равенствам — НайтиСтроки(); условие со сравнением, подстрокой или «ИЛИ» — цикл; пользовательская задача в форме — Ctrl+F. Для массовых обработок, где табличные части читаются из множества документов, эффективнее запрос с обращением к табличной части через точку: РеализацияТоваровУслуг.Товары как источник данных.
Сравнение вариантов
Одна строка по точному равенству реквизита. Не работает в ДанныеФормыКоллекция управляемой формы
Массив строк по структуре отбора с условиями по И. Универсален: работает и с объектом, и с данными формы
Любые условия: сравнения, подстроки, функции. Чуть больше кода, удалять строки внутри нельзя
Поиск по множеству документов сразу, группировки и итоги. Только чтение, изменять объект нужно отдельно
Интерактивный поиск пользователем без кода. Ищет по отображаемому значению одной колонки
Признак правильно выбранного и корректно работающего поиска: на тестовом документе с заведомо известным содержимым находятся именно те строки, которые ожидались, а на документе без совпадений код отрабатывает без ошибок и выдаёт понятное сообщение.
Как проверить результат
Найти()/НайтиСтроки() возвращает именно эту строку, реквизиты совпадают
Возвращается Неопределено или другая строка — проверьте тип и значение отбора
Найти() вернул Неопределено, НайтиСтроки() — пустой массив, ошибок нет
Ошибка выполнения — значит, нет проверки результата
НайтиСтроки() возвращает все строки-дубли
Найдена только первая — возможно, использован Найти() вместо НайтиСтроки()
Курсор таблицы встаёт на найденную строку
Таблица не двигается — проверьте ПолучитьИдентификатор()
Частые вопросы
Как найти строку по двум реквизитам одновременно?
Используйте НайтиСтроки() со структурой из двух элементов: Отбор.Вставить("Номенклатура", Товар); Отбор.Вставить("Склад", Склад). Условия объединяются по «И». Если нужна только первая строка, возьмите нулевой элемент полученного массива после проверки его длины.
Как найти строку по части наименования товара?
Методы Найти() и НайтиСтроки() работают только на точное равенство, поэтому нужен перебор в цикле с функцией СтрНайти(): если СтрНайти(СтрокаТовара.Номенклатура.Наименование, Фрагмент) > 0 — строка подходит. Учтите, что обращение к наименованию через точку вызывает обращение к данным ссылки.
Почему Найти() не находит строку, хотя товар в табличной части есть?
Чаще всего причина в несовпадении типов: в отбор передана строка с наименованием или кодом, а реквизит хранит ссылку на справочник. Передавайте в Найти() именно ссылку на элемент. Также проверьте, что в значении нет лишних пробелов и что поиск идёт по той табличной части (например, «Товары», а не «Услуги»).
Как удалить все найденные строки?
Сначала получите массив через НайтиСтроки(Отбор), затем в цикле по массиву вызовите Объект.Товары.Удалить(СтрокаМассива). Удалять строки прямо внутри перебора самой табличной части нельзя — коллекция изменится во время итерации.
Как узнать номер найденной строки?
У строки табличной части есть свойство НомерСтроки (нумерация с единицы). Также индекс можно получить методом Объект.Товары.Индекс(НайденнаяСтрока) — он возвращает позицию с нуля. В управляемой форме для позиционирования используйте ПолучитьИдентификатор(), а не номер строки.
Чем поиск в табличной части отличается от поиска запросом?
Методы Найти() и НайтиСтроки() работают с уже загруженным в память объектом и позволяют сразу менять строки. Запрос обращается к базе данных, может искать по табличным частям множества документов сразу и строить итоги, но возвращает только данные для чтения — для изменения документ его всё равно нужно получить объектом.
Что важно запомнить
Точное равенство и одна строка — Найти() с обязательной проверкой на Неопределено; выборка по отбору — НайтиСтроки() со структурой; сложные условия — цикл Для Каждого. В управляемой форме доступен только НайтиСтроки(), а позиционирование выполняется через ПолучитьИдентификатор(). Пользователю без кода достаточно Ctrl+F в таблице документа.