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