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

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

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

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

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

Платформа 1С предлагает несколько способов выборки: метод НайтиСтроки() с отбором по структуре, Найти() для поиска одного значения, обход в цикле, а также передачу таблицы значений в запрос как параметра с последующей фильтрацией средствами языка запросов. У каждого подхода есть свои ограничения по скорости, типам сравнения и удобству кода.

Ниже разобраны рабочие приёмы выборки данных из таблицы значений с примерами кода, типичными ошибками и способами проверить, что отбор сработал правильно.

Что такое таблица значений и как она устроена

Таблица значений (объект ТаблицаЗначений) — это несохраняемая в базе структура данных в памяти, состоящая из колонок и строк. Каждая колонка имеет имя и тип значения, каждая строка — набор значений по этим колонкам. Доступ к данным возможен по индексу строки, по имени колонки или через перебор коллекции строк.

Создать таблицу можно программно:

ТЗ = Новый ТаблицаЗначений;

ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));

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

НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000001");

НоваяСтрока.Количество = 5;

НоваяСтрока.Цена = 1200;

Чаще таблица значений появляется как результат выгрузки запроса (Запрос.Выполнить().Выгрузить()), табличной части документа (Документ.Товары.Выгрузить()) или при обмене данными между процедурами. Дальнейшая работа — выборка нужных строк — строится одинаково независимо от источника.

Выборка строк методом НайтиСтроки() с отбором

Основной способ выбрать данные из таблицы значений по условию — метод НайтиСтроки(). Он принимает структуру, где ключи — имена колонок, а значения — искомые значения, и возвращает массив строк, удовлетворяющих всем условиям одновременно (логическое «И»).

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

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

Отбор.Вставить("Количество", 5);

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

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

Сообщить("Цена: " + Строка.Цена);

КонецЦикла;

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

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

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

Когда нужна одна строка, а не массив, используется метод Найти(). Он возвращает первую найденную строку или Неопределено, если совпадений нет. Метод работает в двух вариантах: поиск значения в конкретной колонке или поиск по структуре отбора.

// Поиск по значению в одной колонке

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

// Поиск по структуре отбора

Отбор = Новый Структура("Номенклатура, Количество", ИскомаяНоменклатура, 5);

СтрокаТовара = ТЗ.Найти(Отбор);

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

Сообщить("Строка не найдена");

Иначе

Сообщить("Цена: " + СтрокаТовара.Цена);

КонецЕсли;

Обязательно проверяйте результат на Неопределено перед обращением к полям строки. Обращение СтрокаТовара.Цена при ненайденной строке вызовет ошибку исполнения и прервёт код. Это одна из самых частых причин падения обработок.

Перебор строк в цикле с произвольным условием

Если условие выборки сложнее равенства — диапазоны, сравнение строк, проверка нескольких вариантов — применяется прямой перебор коллекции строк в цикле Для Каждого. Внутри цикла условие проверяется конструкцией Если.

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

Если Строка.Количество > 10 И Строка.Цена < 1000 Тогда

// Строка подходит под условие

Строка.Цена = Строка.Цена * 0.9; // скидка 10%

КонецЕсли;

КонецЦикла;

Цикл удобен ещё и тем, что позволяет сразу изменять найденные строки, собирать итоги или формировать новую таблицу с отобранными данными. Для выборки в отдельную таблицу создают копию структуры исходной ТЗ и добавляют в неё подходящие строки.

Для доступа по индексу используется цикл со счётчиком: ТЗ[Индекс] вернёт строку с указанной позиции (нумерация с нуля). Это нужно, когда порядок обхода важен или требуется удалять строки во время перебора — тогда цикл идёт от конца таблицы к началу.

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

Выборка через запрос к таблице значений

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

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

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

"ВЫБРАТЬ

| ТЗ.Номенклатура КАК Номенклатура,

| ТЗ.Количество КАК Количество,

| ТЗ.Цена КАК Цена

|ПОМЕСТИТЬ ВТ_Данные

|ИЗ &ТЗ КАК ТЗ

|;

|ВЫБРАТЬ

| Данные.Номенклатура,

| СУММА(Данные.Количество) КАК Количество

|ИЗ ВТ_Данные КАК Данные

|ГДЕ Данные.Цена > &МинЦена

|СГРУППИРОВАТЬ ПО Данные.Номенклатура";

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

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

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

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

Сравнение способов выборки

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

Подходит для отбора по равенству одного или нескольких полей. Быстро и коротко, но не поддерживает условия «больше», «в списке», «содержит»

Найти()

Когда нужна одна строка по простому условию. Требует обязательной проверки на Неопределено

Цикл Для Каждого

Универсален для любых условий и изменения строк на лету. Код длиннее, при больших таблицах медленнее запроса

Запрос с параметром ТЗ

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

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

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

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

Если НайденныеСтроки.Количество() = 0 Тогда

Сообщить("По условию ничего не найдено");

Иначе

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

Сообщить(Строка(Строка.Номенклатура) + " — " + Строка.Количество);

КонецЦикла;

КонецЕсли;

Для сверки итогов удобен метод Итог(): ТЗ.Итог("Количество") вернёт сумму по колонке. Если выборка формируется в новую таблицу, сравните итоги исходной и отобранной таблиц — расхождение без видимой причины указывает на ошибку в условии отбора.

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

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

Количество найденных строк
Норма

Совпадает с ожидаемым числом по тестовым данным

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

Пустой массив при заведомо существующих данных — проверьте типы значений в отборе

Содержимое первой строки
Норма

Значения полей соответствуют условию отбора

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

Поля пустые или не того типа — проверьте имена колонок и заполнение ТЗ

Итоги по числовым колонкам
Норма

Сумма отобранных строк сходится с контрольным значением

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

Итог не сходится — условие отбора шире или уже задуманного

Производительность и ограничения

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

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

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

FAQ: частые вопросы о выборке из таблицы значений

Как выбрать строки, где значение колонки входит в список значений?

Методом НайтиСтроки() это не сделать — он работает только на равенство. Используйте цикл с проверкой Список.НайтиПоЗначению(Строка.Колонка) <> Неопределено или передайте ТЗ в запрос с условием ГДЕ Колонка В (&Список).

Чем отличается Найти() от НайтиСтроки()?

Найти() возвращает одну первую подходящую строку или Неопределено. НайтиСтроки() возвращает массив всех подходящих строк, возможно пустой. Для обоих методов условие — только строгое равенство.

Как удалить из таблицы значений строки по условию?

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

Можно ли отсортировать таблицу значений перед выборкой?

Да, методом ТЗ.Сортировать("Цена Убыв, Номенклатура") — указываются имена колонок и направление. Сортировка меняет порядок строк в самой таблице и полезна, когда результат выборки должен выводиться пользователю в определённом порядке.

Как выбрать уникальные значения одной колонки?

Используйте ТЗ.Скопировать(, "Номенклатура") для копии с одной колонкой и затем Копия.Свернуть("Номенклатура") — останутся только уникальные значения. Либо выгрузите колонку через ТЗ.ВыгрузитьКолонку("Номенклатура") и обработайте массив.

Почему НайтиСтроки() не находит строку, хотя значение в таблице есть?

Чаще всего причина в несовпадении типов: в колонке строка, а в отборе число, или ссылка относится к другому виду справочника. Также проверьте лишние пробелы и регистр в строковых значениях — сравнение строк выполняется точное.

Итог

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

Для простого отбора по равенству используйте НайтиСтроки() или Найти() с обязательной проверкой результата. Сложные условия решайте циклом или запросом с передачей ТЗ как параметра. Следите за типами значений в отборе и проверяйте количество и итоги отобранных строк.