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