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