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