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

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

Как сделать отбор строк в таблице значений 1С

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

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

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

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

Какие способы отбора строк существуют и когда их применять

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

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

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

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

Возвращает массив строк по условию. Подходит для обработки, удаления и копирования. На больших таблицах работает полным перебором.

Найти()

Возвращает первую найденную строку или Неопределено. Оптимален для поиска по уникальному ключу.

Скопировать(МассивСтрок)

Создаёт новую таблицу значений из отобранных строк. Подходит, когда результат нужен как отдельная таблица.

Отбор на форме

Меняет только отображение данных, строки в таблице сохраняются. Подходит для интерактивной фильтрации.

Отбор через НайтиСтроки: базовый синтаксис

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

// Таблица ТЗ содержит колонки Номенклатура, Склад, Количество

ПараметрыОтбора = Новый Структура("Склад", СкладОсновной);

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

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

Строка.Количество = Строка.Количество * 2;

КонецЦикла;

Отбор возможен сразу по нескольким колонкам — условия объединяются по принципу «И», то есть строка попадёт в результат, только если совпадут все значения:

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

ПараметрыОтбора.Вставить("Склад", СкладОсновной);

ПараметрыОтбора.Вставить("Номенклатура", ТекущаяНоменклатура);

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

Важно понимать: сравнение выполняется на точное равенство с учётом типа. Если в колонке хранится ссылка на справочник, а в отбор передана строка с наименованием, совпадений не будет. То же относится к числам, переданным строкой, и наоборот.

Поиск одной строки методом Найти

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

СтрокаТовара = ТЗ.Найти(КодТовара, "Код");

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

// строки нет — добавляем или сообщаем пользователю

СтрокаТовара = ТЗ.Добавить();

СтрокаТовара.Код = КодТовара;

КонецЕсли;

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

Первый параметр — искомое значение, второй — имя колонки (или список колонок через запятую). Если второй параметр не указан, поиск идёт по всем колонкам, что на больших таблицах заметно медленнее.

bsl
СтрокаТовара = ТЗ.Найти(КодТовара, "Код");
Если СтрокаТовара = Неопределено Тогда
    Сообщить("Строка не найдена");
КонецЕсли;

Получение новой таблицы с отобранными строками

Если отобранные строки нужны как самостоятельная таблица — например, для передачи в процедуру, выгрузки или заполнения другого объекта — используется связка НайтиСтроки() и Скопировать():

ПараметрыОтбора = Новый Структура("Склад", СкладОсновной);

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

ТЗПоСкладу = ТЗ.Скопировать(НайденныеСтроки);

// ТЗПоСкладу — новая таблица значений только со строками по складу

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

Учитывайте, что Скопировать() создаёт полную копию данных в памяти. Для очень больших таблиц, если нужна только обработка, а не отдельная таблица, дешевле обойтись массивом строк без копирования.

Отбор строк на форме без изменения данных

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

// Реквизит формы Товары — таблица значений

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

Для динамических списков и таблиц, связанных с ними, применяется стандартный механизм отбора через ЭлементыОтбора. Снять отбор можно, присвоив Неопределено:

Элементы.Товары.ОтборСтрок = Неопределено;

Частая ошибка — попытаться установить отбор на форме и одновременно физически удалить строки из таблицы. В результате пользователь теряет данные, которые ещё могли понадобиться. Если отбор носит временный характер, всегда предпочитайте ОтборСтрок удалению строк.

Отбор по сложным условиям: больше, меньше, не равно

Структура отбора в НайтиСтроки() поддерживает только равенство. Если нужно условие «количество больше нуля», «дата в интервале» или «не равно значению», применяется прямой перебор строк с проверкой условия:

Для Каждого Строка Из ТЗ Цикл

Если Строка.Количество > 0 И Строка.Дата >= НачалоПериода Тогда

// обработка строки

КонецЕсли;

КонецЦикла;

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ Т.Номенклатура, Т.Количество

|ПОМЕСТИТЬ ВТ ИЗ &ТЗ КАК Т

|;

|ВЫБРАТЬ * ИЗ ВТ ГДЕ ВТ.Количество > &Минимум";

Запрос.УстановитьПараметр("ТЗ", ТЗ);

Запрос.УстановитьПараметр("Минимум", 10);

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

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

Маршрут решения

Как выбрать способ отбора

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

Типичные ошибки и как их избежать

Первая и самая распространённая ошибка — несовпадение типов. Отбор по строковому представлению ссылки или по числу, записанному строкой, всегда даёт пустой результат, и внешне код выглядит правильным. Проверяйте тип значения в колонке через отладчик или метод ТипЗнч().

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

НайденныеСтроки = ТЗ.НайтиСтроки(Новый Структура("Пометка", Истина));

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

ТЗ.Удалить(Строка);

КонецЦикла;

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

Типичные ошибки
01
Отбор значением другого типа — результат всегда пустой, ошибки при выполнении нет
02
Обращение к результату Найти() без проверки на Неопределено — ошибка выполнения при отсутствии строки
03
Опечатка в имени колонки в структуре отбора — исключение в момент вызова НайтиСтроки
04
Удаление строк при прямом переборе таблицы сверху вниз — пропуск части строк
05
Ожидание, что Скопировать() сохранит связь с исходной таблицей — изменения в копии не попадают в оригинал

Как проверить, что отбор сработал правильно

Минимальная проверка — количество элементов в массиве результата. Если ожидалась хотя бы одна строка, а массив пуст, сначала сверьте типы значений и точные значения в колонке через отладчик. Полезно вывести в сообщение значения нескольких строк таблицы и сравнить их с параметром отбора визуально.

Для отбора на форме проверка простая: после установки ОтборСтрок таблица на форме должна показать только нужные строки, а при снятии отбора — вернуться к полному составу. Если строки «пропали» безвозвратно, значит, в коде где-то выполняется физическое удаление, а не отбор.

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

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

Размер массива НайденныеСтроки
Норма

Количество соответствует ожиданиям по данным

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

Массив пуст при заведомо подходящих данных — проверяйте типы и значения

Результат Найти()
Норма

Возвращена строка, поля доступны

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

Неопределено — значение не найдено, нужна ветка обработки

Поведение таблицы на форме
Норма

Строки фильтруются и возвращаются при снятии отбора

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

Строки исчезают насовсем — где-то выполняется удаление

Тип значения отбора
Норма

Тип совпадает с типом данных колонки

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

Строка вместо ссылки/числа — совпадений не будет

Вопросы и ответы

Можно ли в НайтиСтроки задать условие «не равно»?

Нет, структура отбора поддерживает только равенство. Для условия «не равно» переберите строки в цикле с проверкой через «Если НЕ Строка.Колонка = Значение Тогда» и соберите подходящие строки в отдельный массив или обработайте их прямо в цикле.

Как отобрать строки по нескольким значениям одной колонки (список значений)?

Напрямую список в структуру отбора передать нельзя. Варианты: выполнить НайтиСтроки для каждого значения и объединить массивы, либо перебрать таблицу в цикле с проверкой СписокЗначений.НайтиПоЗначению(Строка.Колонка) <> Неопределено. Для больших таблиц удобнее запрос с условием «В (&Список)».

Изменятся ли исходные данные, если изменить строку из массива НайтиСтроки?

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

Что быстрее: НайтиСтроки или перебор в цикле?

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

Как отобрать строки по части строки (подобно)?

Через структуру отбора — никак. Используйте перебор с функцией СтрНайти(Строка.Наименование, Подстрока) > 0, либо выгрузите таблицу в запрос и примените оператор ПОДОБНО с шаблоном "%подстрока%". Учтите, что оба варианта на больших таблицах работают медленнее точного отбора.

Почему отбор на форме не применяется, хотя код выполняется без ошибок?

Чаще всего причина в том, что ОтборСтрок устанавливается не у того элемента формы или таблица привязана к динамическому списку, где нужен другой механизм отбора. Также проверьте, что имя колонки в отборе точно совпадает с именем колонки реквизита формы, и что после установки отбора таблица не перезаполняется заново.

Итог

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

Для отбора по равенству используйте НайтиСтроки со структурой отбора, для одной строки — Найти с проверкой на Неопределено, для новой таблицы — Скопировать, для отображения на форме — ОтборСтрок. Следите за типами значений, не удаляйте строки при прямом переборе и проверяйте результат по количеству найденных строк.