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