Работа с таблицей значений в коде 1С: от создания до свёртки

· 9 мин

Содержание

Таблица значений создаётся в коде одной строкой ТЗ = Новый ТаблицаЗначений;, дальше к ней добавляют колонки через ТЗ.Колонки.Добавить(...) и строки через ТЗ.Добавить(). Это универсальный контейнер «в памяти»: строки и колонки, как в Excel, но живёт только пока выполняется код и в базе не хранится.

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

В управляемом приложении таблица значений доступна только на сервере и в толстом клиенте. В процедуре &НаКлиенте тонкого клиента Новый ТаблицаЗначений вызовет ошибку. Создавайте её в серверном методе.

Что такое таблица значений и когда она нужна

Таблица значений (ТЗ) — объект встроенного языка для хранения табличных данных в оперативной памяти. У неё есть коллекция колонок с именами и типами и коллекция строк. Обращение к ячейке — через имя колонки: ТЗ[0].Количество.

Её берут там, где нужна временная таблица, не привязанная к объектам базы:

  • 📊 собрать данные из запроса и обработать их в коде;
  • 🔁 передать набор строк между процедурами или в другую обработку;
  • 🧮 посчитать итоги , сгруппировать, отфильтровать без обращения к базе;
  • 📄 подготовить данные для табличного поля формы или печатной формы.

От похожих объектов ТЗ отличается структурой. СписокЗначений — одномерный список, одна «колонка». Структура и Соответствие — пары ключ-значение без строк. ДеревоЗначений — те же колонки, но со вложенными строками (иерархия). Когда нужны именно строки с несколькими полями — это таблица значений.

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

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

Сам объект создаётся пустым:

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

Дальше описываем колонки. У метода Колонки.Добавить четыре параметра: имя, тип значения, заголовок для показа на форме и ширина. Обязательно только имя:

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

Тип задаётся объектом ОписаниеТипов. Для чисел можно уточнить разрядность и знак:

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

Если тип не указать (как у колонки Комментарий), ячейка примет значение любого типа. Это удобно, но из-за непредсказуемых типов потом сложнее сортировать и сравнивать — указывайте тип, когда он известен заранее.

💡 Имя колонки — это идентификатор для кода (Строка.Номенклатура), заголовок — подпись в табличном поле. Это разные вещи: имя не может содержать пробелов, заголовок может быть любым.

Как добавить строки и заполнить данные

Новая строка добавляется методом Добавить(), он возвращает саму строку — её поля заполняем по имени колонки:

НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = ВыбраннаяНоменклатура;
НоваяСтрока.Количество = 5;
НоваяСтрока.Цена = 1200;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;

Если строку нужно вставить в конкретную позицию, а не в конец, используйте Вставить(Индекс):

ПерваяСтрока = ТЗ.Вставить(0);

Чтобы заполнить таблицу готовыми данными из результата запроса, строки писать вручную не нужно — метод Выгрузить() создаёт таблицу с колонками по полям запроса:

Запрос = Новый Запрос;
Запрос.Текст =
	"ВЫБРАТЬ
	|	Товары.Номенклатура КАК Номенклатура,
	|	Товары.Количество КАК Количество,
	|	Товары.Сумма КАК Сумма
	|ИЗ
	|	Документ.РеализацияТоваровУслуг.Товары КАК Товары
	|ГДЕ
	|	Товары.Ссылка = &Документ";
Запрос.УстановитьПараметр("Документ", СсылкаНаДокумент);
ТЗ = Запрос.Выполнить().Выгрузить();

Такой способ быстрее поэлементного заполнения: платформа создаёт колонки и строки за один вызов. Когда данные уже лежат в табличной части документа, их тоже можно выгрузить в ТЗ методом ТабличнаяЧасть.Выгрузить().

Количество строк — свойство-метод ТЗ.Количество(). Обойти все строки удобнее циклом по коллекции:

Для Каждого Строка Из ТЗ Цикл
	Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;

Редактирование колонок: добавить, удалить, сменить тип

Колонки — это коллекция ТЗ.Колонки со своими методами. Добавление мы разобрали выше. Остальные операции:

  • удалить колонку — ТЗ.Колонки.Удалить("Комментарий") или по индексу;
  • узнать число колонок — ТЗ.Колонки.Количество();
  • найти колонку по имени — ТЗ.Колонки.Найти("Цена") (вернёт колонку или Неопределено);
  • переименовать или сменить заголовок — через свойства найденной колонки: Колонка.Заголовок = "Цена с НДС".

Прямого способа «поменять тип уже заполненной колонки» нет. Тип задаётся при создании. Если он выбран неверно, колонку удаляют и добавляют заново с нужным ОписаниеТипов, а значения переносят. Поэтому тип лучше продумать заранее.

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

ТЗ.Колонки.Добавить("СуммаСНДС", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из ТЗ Цикл
	Строка.СуммаСНДС = Строка.Сумма * 1.2;
КонецЦикла;

Сортировка, поиск и фильтрация строк

Сортируют таблицу методом Сортировать. В строке перечисляют колонки и направление: Возр (по возрастанию, по умолчанию) или Убыв:

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

Для поиска одной строки по значению есть Найти — ищет значение в указанных колонках и возвращает первую подходящую строку или Неопределено:

НайденнаяСтрока = ТЗ.Найти(ВыбраннаяНоменклатура, "Номенклатура");
Если НайденнаяСтрока <> Неопределено Тогда
	Сообщить(НайденнаяСтрока.Количество);
КонецЕсли;

Когда нужны все строки по условию (фильтрация) — метод НайтиСтроки. Условие задают структурой «имя колонки → значение», метод возвращает массив строк:

Отбор = Новый Структура("Номенклатура", ВыбраннаяНоменклатура);
Строки = ТЗ.НайтиСтроки(Отбор);
Для Каждого Строка Из Строки Цикл
	// обработка отобранных строк
КонецЦикла;

В структуру отбора можно положить несколько колонок — тогда условия объединяются по «И». Строгого «больше/меньше» в НайтиСтроки нет: для диапазонов или сравнений обходят таблицу циклом и проверяют условие вручную.

💡 НайтиСтроки при отсутствии совпадений возвращает пустой массив, а не Неопределено. Проверять результат нужно через Строки.Количество() = 0, иначе условие Если Строки = Неопределено никогда не сработает. А метод Найти наоборот — отдаёт Неопределено, когда ничего не нашлось.

Чтобы вытащить значения одной колонки в массив (например, список всех ссылок для запроса), есть ВыгрузитьКолонку:

МассивНоменклатуры = ТЗ.ВыгрузитьКолонку("Номенклатура");

Практические приёмы: свёртка, итоги, копирование

Самый частый приём обработки — свёртка (группировка с суммированием). Метод Свернуть оставляет уникальные комбинации группировочных колонок и складывает суммируемые:

// группируем по номенклатуре, суммируем количество и сумму
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");

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

Итог по колонке считается методом Итог:

ОбщаяСумма = ТЗ.Итог("Сумма");

Копия таблицы делается методом Скопировать. Без параметров он вернёт полную копию; можно скопировать только часть строк и колонок:

КопияТЗ = ТЗ.Скопировать(); // полная независимая копия
ТолькоТовары = ТЗ.Скопировать(Строки, "Номенклатура, Количество");

Отдельная задача — показать таблицу на управляемой форме. Напрямую объект ТЗ на клиенте недоступен, поэтому его либо делают реквизитом формы типа «ТаблицаЗначений» (платформа сама преобразует его в данные формы), либо переносят методами ЗначениеВДанныеФормы и ДанныеФормыВЗначение:

&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
	ТЗ = ПолучитьДанные(); // вернула ТаблицаЗначений
	ЗначениеВДанныеФормы(ТЗ, ТаблицаНаФорме);
КонецПроцедуры

Собрать несколько приёмов в один сценарий проще на коротком примере. Задача: из строк документа получить итоги по номенклатуре, отсортировать по убыванию суммы и узнать общую сумму.

// 1. выгрузили строки табличной части в ТЗ
ТЗ = Документ.Товары.Выгрузить("Номенклатура, Количество, Сумма");

// 2. свернули по номенклатуре с суммированием
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");

// 3. отсортировали по сумме, самые крупные сверху
ТЗ.Сортировать("Сумма Убыв");

// 4. посчитали общий итог
ОбщаяСумма = ТЗ.Итог("Сумма");

Четыре строки заменяют ручной цикл с накоплением в Соответствие — и читаются понятнее. Это типовой скелет почти любой обработки данных через таблицу значений: выгрузили из источника, свернули, отсортировали, посчитали итог.

Короткая шпаргалка по методам, которые используют чаще всего:

МетодЧто делает
Добавить() / Вставить(Индекс)новая строка в конец или в позицию
Удалить(Строка)удаляет строку
Количество()число строк
Найти(Знач, "Колонки")первая строка по значению
НайтиСтроки(Отбор)массив строк по условию
Сортировать("Колонка Убыв")сортировка
Свернуть("Группировка", "Сумма")группировка с суммированием
Итог("Колонка")сумма по колонке
ВыгрузитьКолонку("Имя")значения колонки в массив
Скопировать()независимая копия

Оптимизация работы с большими таблицами

Пока строк немного, скорость не важна. На десятках и сотнях тысяч строк разница между приёмами становится заметной.

Главный инструмент ускорения поиска — индексы. Если по таблице многократно вызывается НайтиСтроки по одним и тем же колонкам, добавьте индекс — поиск пойдёт не перебором, а по индексу:

ТЗ.Индексы.Добавить("Номенклатура");
ТЗ.Индексы.Добавить("Номенклатура, Склад");

Ещё несколько правил для больших объёмов:

  • 🚀 заполняйте таблицу через Запрос.Выполнить().Выгрузить(), а не строку за строкой в цикле — это на порядок быстрее;
  • 🧱 для массовой загрузки или выгрузки столбца используйте ЗагрузитьКолонку / ВыгрузитьКолонку вместо поэлементного цикла (например, ТЗ.ЗагрузитьКолонку(МассивЦен, "Цена") запишет весь столбец одним вызовом);
  • 🔄 группировку делайте методом Свернуть, а не ручным накоплением итогов в цикле;
  • 🧮 если данные всё равно берутся из базы и объём большой, иногда выгоднее посчитать всё в запросе (временные таблицы, виртуальные таблицы), а в ТЗ выгрузить уже готовый результат.

Удаление строк в прямом цикле Для Каждого — частая причина пропущенных строк: после удаления коллекция сдвигается. Удаляйте в обратном цикле по индексу:

Для Сч = ТЗ.Количество() - 1 По 0 Цикл
	Если ТЗ[Сч].Количество = 0 Тогда
		ТЗ.Удалить(Сч);
	КонецЕсли;
КонецЦикла;

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

Ниже — не повтор шагов, а ситуации, где код падает или ведёт себя неожиданно, с причиной и решением.

Диагностика: выберите симптом

Частые вопросы

Чем таблица значений отличается от списка значений?
СписокЗначений хранит одномерный список элементов (значение плюс представление и пометка), а таблица значений — это строки с несколькими именованными колонками. Для набора записей с полями берут таблицу, для простого перечня — список.
Сохраняется ли таблица значений в базе данных?
Нет. ТЗ живёт только в оперативной памяти во время выполнения кода. Для постоянного хранения используют табличные части объектов, регистры или сериализацию в хранилище значений.
Можно ли передать таблицу значений в табличную часть документа?
Да, методом ТабличнаяЧасть.Загрузить(ТЗ). Колонки таблицы значений должны совпадать по именам и типам с реквизитами табличной части, иначе значения не перенесутся.
Как получить таблицу значений из результата запроса?
Вызвать Выгрузить() у результата: ТЗ = Запрос.Выполнить().Выгрузить();. Колонки создадутся автоматически по полям и псевдонимам запроса.
Почему таблица значений недоступна на клиенте?
В управляемом приложении этот объект существует только на сервере и в толстом клиенте. На тонком клиенте с ней работают через реквизит формы или преобразование ДанныеФормыВЗначение / ЗначениеВДанныеФормы.