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