Работа с таблицей значений в коде 1С: от создания до свёртки
Содержание
Таблица значений создаётся в коде одной строкой ТЗ = Новый ТаблицаЗначений;, дальше к ней добавляют колонки через ТЗ.Колонки.Добавить(...) и строки через ТЗ.Добавить(). Это универсальный контейнер «в памяти»: строки и колонки, как в Excel, но живёт только пока выполняется код и в базе не хранится.
Заполнять таблицу значений удобно двумя путями — вручную строка за строкой или сразу из результата запроса методом Выгрузить(). Обрабатывать — сортировать, искать строки, сворачивать с суммированием, выгружать колонку в массив. Ниже разберём весь цикл: создание, наполнение данными, редактирование колонок, поиск и оптимизацию для больших объёмов.
В управляемом приложении таблица значений доступна только на сервере и в толстом клиенте. В процедуре &НаКлиенте тонкого клиента Новый ТаблицаЗначений вызовет ошибку. Создавайте её в серверном методе.
Что такое таблица значений и когда она нужна
Таблица значений (ТЗ) — объект встроенного языка для хранения табличных данных в оперативной памяти. У неё есть коллекция колонок с именами и типами и коллекция строк. Обращение к ячейке — через имя колонки: ТЗ[0].Количество.
Её берут там, где нужна временная таблица, не привязанная к объектам базы:
- 📊 собрать данные из запроса и обработать их в коде;
- 🔁 передать набор строк между процедурами или в другую обработку;
- 🧮 посчитать итоги , сгруппировать, отфильтровать без обращения к базе;
- 📄 подготовить данные для табличного поля формы или печатной формы.
От похожих объектов ТЗ отличается структурой. СписокЗначений — одномерный список, одна «колонка». Структура и Соответствие — пары ключ-значение без строк. ДеревоЗначений — те же колонки, но со вложенными строками (иерархия). Когда нужны именно строки с несколькими полями — это таблица значений.
Есть и обратная сторона: таблица значений — не всегда лучший выбор. Если данные нужно только отобрать и показать, зачастую проще работать с результатом запроса напрямую или с динамическим списком на форме. Если по набору идёт поиск одного значения по ключу — быстрее Соответствие. Таблицу значений берут, когда строки нужно многократно перебирать, менять, сортировать и сворачивать в памяти.
Создание таблицы значений и описание колонок
Сам объект создаётся пустым:
ТЗ = Новый ТаблицаЗначений;
Дальше описываем колонки. У метода Колонки.Добавить четыре параметра: имя, тип значения, заголовок для показа на форме и ширина. Обязательно только имя:
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"), "Цена, руб.");
ТЗ.Колонки.Добавить("Комментарий");
Тип задаётся объектом ОписаниеТипов. Для чисел можно уточнить разрядность и знак:
КвалЧисла = Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный);
ОписаниеЧисла = Новый ОписаниеТипов("Число", КвалЧисла);
ТЗ.Колонки.Добавить("Сумма", ОписаниеЧисла);
Если тип не указать (как у колонки Комментарий), ячейка примет значение любого типа. Это удобно, но из-за непредсказуемых типов потом сложнее сортировать и сравнивать — указывайте тип, когда он известен заранее.
💡 Имя колонки — это идентификатор для кода (Строка.Номенклатура), заголовок — подпись в табличном поле. Это разные вещи: имя не может содержать пробелов, заголовок может быть любым.
Как добавить строки и заполнить данные
Новая строка добавляется методом Добавить(), он возвращает саму строку — её поля заполняем по имени колонки:
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = ВыбраннаяНоменклатура;
НоваяСтрока.Количество = 5;
НоваяСтрока.Цена = 1200;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;
Если строку нужно вставить в конкретную позицию, а не в конец, используйте Вставить(Индекс):
ПерваяСтрока = ТЗ.Вставить(0);
Чтобы заполнить таблицу готовыми данными из результата запроса, строки писать вручную не нужно — метод Выгрузить() создаёт таблицу с колонками по полям запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Количество КАК Количество,
| Товары.Сумма КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Документ";
Запрос.УстановитьПараметр("Документ", СсылкаНаДокумент);
ТЗ = Запрос.Выполнить().Выгрузить();
Такой способ быстрее поэлементного заполнения: платформа создаёт колонки и строки за один вызов. Когда данные уже лежат в табличной части документа, их тоже можно выгрузить в ТЗ методом ТабличнаяЧасть.Выгрузить().
Количество строк — свойство-метод ТЗ.Количество(). Обойти все строки удобнее циклом по коллекции:
Для Каждого Строка Из ТЗ Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
Редактирование колонок: добавить, удалить, сменить тип
Колонки — это коллекция ТЗ.Колонки со своими методами. Добавление мы разобрали выше. Остальные операции:
- удалить колонку —
ТЗ.Колонки.Удалить("Комментарий")или по индексу; - узнать число колонок —
ТЗ.Колонки.Количество(); - найти колонку по имени —
ТЗ.Колонки.Найти("Цена")(вернёт колонку илиНеопределено); - переименовать или сменить заголовок — через свойства найденной колонки:
Колонка.Заголовок = "Цена с НДС".
Прямого способа «поменять тип уже заполненной колонки» нет. Тип задаётся при создании. Если он выбран неверно, колонку удаляют и добавляют заново с нужным ОписаниеТипов, а значения переносят. Поэтому тип лучше продумать заранее.
Если нужно добавить колонку в уже заполненную таблицу, значения в ней у всех строк будут пустыми — заполните их отдельным циклом:
ТЗ.Колонки.Добавить("СуммаСНДС", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из ТЗ Цикл
Строка.СуммаСНДС = Строка.Сумма * 1.2;
КонецЦикла;
Сортировка, поиск и фильтрация строк
Сортируют таблицу методом Сортировать. В строке перечисляют колонки и направление: Возр (по возрастанию, по умолчанию) или Убыв:
ТЗ.Сортировать("Количество Убыв, Номенклатура Возр");
Для поиска одной строки по значению есть Найти — ищет значение в указанных колонках и возвращает первую подходящую строку или Неопределено:
НайденнаяСтрока = ТЗ.Найти(ВыбраннаяНоменклатура, "Номенклатура");
Если НайденнаяСтрока <> Неопределено Тогда
Сообщить(НайденнаяСтрока.Количество);
КонецЕсли;
Когда нужны все строки по условию (фильтрация) — метод НайтиСтроки. Условие задают структурой «имя колонки → значение», метод возвращает массив строк:
Отбор = Новый Структура("Номенклатура", ВыбраннаяНоменклатура);
Строки = ТЗ.НайтиСтроки(Отбор);
Для Каждого Строка Из Строки Цикл
// обработка отобранных строк
КонецЦикла;
В структуру отбора можно положить несколько колонок — тогда условия объединяются по «И». Строгого «больше/меньше» в НайтиСтроки нет: для диапазонов или сравнений обходят таблицу циклом и проверяют условие вручную.
💡 НайтиСтроки при отсутствии совпадений возвращает пустой массив, а не Неопределено. Проверять результат нужно через Строки.Количество() = 0, иначе условие Если Строки = Неопределено никогда не сработает. А метод Найти наоборот — отдаёт Неопределено, когда ничего не нашлось.
Чтобы вытащить значения одной колонки в массив (например, список всех ссылок для запроса), есть ВыгрузитьКолонку:
МассивНоменклатуры = ТЗ.ВыгрузитьКолонку("Номенклатура");
Практические приёмы: свёртка, итоги, копирование
Самый частый приём обработки — свёртка (группировка с суммированием). Метод Свернуть оставляет уникальные комбинации группировочных колонок и складывает суммируемые:
// группируем по номенклатуре, суммируем количество и сумму
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");
После Свернуть в таблице останутся только перечисленные колонки — остальные удаляются. Если нужно сохранить исходник, сначала скопируйте его.
Итог по колонке считается методом Итог:
ОбщаяСумма = ТЗ.Итог("Сумма");
Копия таблицы делается методом Скопировать. Без параметров он вернёт полную копию; можно скопировать только часть строк и колонок:
КопияТЗ = ТЗ.Скопировать(); // полная независимая копия
ТолькоТовары = ТЗ.Скопировать(Строки, "Номенклатура, Количество");
Отдельная задача — показать таблицу на управляемой форме. Напрямую объект ТЗ на клиенте недоступен, поэтому его либо делают реквизитом формы типа «ТаблицаЗначений» (платформа сама преобразует его в данные формы), либо переносят методами ЗначениеВДанныеФормы и ДанныеФормыВЗначение:
&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
ТЗ = ПолучитьДанные(); // вернула ТаблицаЗначений
ЗначениеВДанныеФормы(ТЗ, ТаблицаНаФорме);
КонецПроцедуры
Собрать несколько приёмов в один сценарий проще на коротком примере. Задача: из строк документа получить итоги по номенклатуре, отсортировать по убыванию суммы и узнать общую сумму.
// 1. выгрузили строки табличной части в ТЗ
ТЗ = Документ.Товары.Выгрузить("Номенклатура, Количество, Сумма");
// 2. свернули по номенклатуре с суммированием
ТЗ.Свернуть("Номенклатура", "Количество, Сумма");
// 3. отсортировали по сумме, самые крупные сверху
ТЗ.Сортировать("Сумма Убыв");
// 4. посчитали общий итог
ОбщаяСумма = ТЗ.Итог("Сумма");
Четыре строки заменяют ручной цикл с накоплением в Соответствие — и читаются понятнее. Это типовой скелет почти любой обработки данных через таблицу значений: выгрузили из источника, свернули, отсортировали, посчитали итог.
Короткая шпаргалка по методам, которые используют чаще всего:
| Метод | Что делает |
|---|---|
Добавить() / Вставить(Индекс) | новая строка в конец или в позицию |
Удалить(Строка) | удаляет строку |
Количество() | число строк |
Найти(Знач, "Колонки") | первая строка по значению |
НайтиСтроки(Отбор) | массив строк по условию |
Сортировать("Колонка Убыв") | сортировка |
Свернуть("Группировка", "Сумма") | группировка с суммированием |
Итог("Колонка") | сумма по колонке |
ВыгрузитьКолонку("Имя") | значения колонки в массив |
Скопировать() | независимая копия |
Оптимизация работы с большими таблицами
Пока строк немного, скорость не важна. На десятках и сотнях тысяч строк разница между приёмами становится заметной.
Главный инструмент ускорения поиска — индексы. Если по таблице многократно вызывается НайтиСтроки по одним и тем же колонкам, добавьте индекс — поиск пойдёт не перебором, а по индексу:
ТЗ.Индексы.Добавить("Номенклатура");
ТЗ.Индексы.Добавить("Номенклатура, Склад");
Ещё несколько правил для больших объёмов:
- 🚀 заполняйте таблицу через
Запрос.Выполнить().Выгрузить(), а не строку за строкой в цикле — это на порядок быстрее; - 🧱 для массовой загрузки или выгрузки столбца используйте
ЗагрузитьКолонку/ВыгрузитьКолонкувместо поэлементного цикла (например,ТЗ.ЗагрузитьКолонку(МассивЦен, "Цена")запишет весь столбец одним вызовом); - 🔄 группировку делайте методом
Свернуть, а не ручным накоплением итогов в цикле; - 🧮 если данные всё равно берутся из базы и объём большой, иногда выгоднее посчитать всё в запросе (временные таблицы, виртуальные таблицы), а в ТЗ выгрузить уже готовый результат.
Удаление строк в прямом цикле Для Каждого — частая причина пропущенных строк: после удаления коллекция сдвигается. Удаляйте в обратном цикле по индексу:
Для Сч = ТЗ.Количество() - 1 По 0 Цикл
Если ТЗ[Сч].Количество = 0 Тогда
ТЗ.Удалить(Сч);
КонецЕсли;
КонецЦикла;
Частые ошибки при работе с таблицей значений
Ниже — не повтор шагов, а ситуации, где код падает или ведёт себя неожиданно, с причиной и решением.
&НаСервере, а на форму передайте через реквизит типа ТаблицаЗначений или метод ЗначениеВДанныеФормы.Колонки.Добавить (не с заголовком). Проверьте регистр и опечатки; при динамических именах используйте Колонки.Найти(Имя) <> Неопределено.Для Каждого сдвигает индексы. Удаляйте в обратном цикле по индексу от Количество() - 1 до 0.Свернуть оставляет только группировочные и суммируемые колонки. Сохраняйте исходную таблицу через Скопировать() до свёртки, если остальные колонки ещё нужны.Частые вопросы
Чем таблица значений отличается от списка значений?
СписокЗначений хранит одномерный список элементов (значение плюс представление и пометка), а таблица значений — это строки с несколькими именованными колонками. Для набора записей с полями берут таблицу, для простого перечня — список.Сохраняется ли таблица значений в базе данных?
Можно ли передать таблицу значений в табличную часть документа?
ТабличнаяЧасть.Загрузить(ТЗ). Колонки таблицы значений должны совпадать по именам и типам с реквизитами табличной части, иначе значения не перенесутся.Как получить таблицу значений из результата запроса?
Выгрузить() у результата: ТЗ = Запрос.Выполнить().Выгрузить();. Колонки создадутся автоматически по полям и псевдонимам запроса.Почему таблица значений недоступна на клиенте?
ДанныеФормыВЗначение / ЗначениеВДанныеФормы.