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