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