Колонки таблицы значений в 1С 8.3: добавление, типы, заполнение и форма

· 9 мин

Содержание

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

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

Метод Колонки.Добавить(): синтаксис и первый пример

Таблица значений создаётся конструктором, а колонки живут в её свойстве Колонки — это коллекция КоллекцияКолонокТаблицыЗначений. Добавлять колонки можно и в пустую, и в уже заполненную таблицу.

Полный синтаксис:

Колонки.Добавить(<Имя>, <ТипЗначения>, <Заголовок>, <Ширина>)
ПараметрЧто задаётОбязателен
ИмяИдентификатор колонки, по нему идёт обращение Строка.ИмяДа
ТипЗначенияОбъект ОписаниеТипов — какие значения допустимыНет
ЗаголовокТекст, который увидит пользователь при выводеНет
ШиринаШирина колонки в символах при отображенииНет

Минимальный рабочий пример — таблица товаров из трёх колонок:

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

НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Количество = 2;
НоваяСтрока.Сумма = 1500;

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

КолонкаЦена = ТЗ.Колонки.Добавить("Цена");
КолонкаЦена.Заголовок = "Цена, руб.";

Вставить колонку в нужную позицию

Добавить() всегда ставит колонку последней. Если порядок важен (например, таблицу потом выводят пользователю или выгружают в файл), используйте Вставить() — у него первым параметром идёт индекс. Нумерация начинается с нуля.

// Колонка "Артикул" станет второй по счёту
ТЗ.Колонки.Вставить(1, "Артикул", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(25)));

Уже существующую колонку можно передвинуть методом Колонки.Сдвинуть(Колонка, Смещение): отрицательное смещение двигает её влево, положительное — вправо.

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

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

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

Проверить, что колонки ещё нет

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

Если ТЗ.Колонки.Найти("Отметка") = Неопределено Тогда
    ТЗ.Колонки.Добавить("Отметка", Новый ОписаниеТипов("Булево"));
КонецЕсли;

Найти() возвращает колонку или Неопределено, если колонки с таким именем нет.

Заполнить новую колонку значениями

Сразу после добавления в старых строках лежат пустые значения. Есть три способа их заполнить:

  1. 🔹 Одно значение во все строки — ЗаполнитьЗначения():
    ТЗ.ЗаполнитьЗначения(Истина, "Отметка");
    
  2. 🔹 Значения из массива — ЗагрузитьКолонку(). Массив должен идти в том же порядке, что и строки:
    ТЗ.ЗагрузитьКолонку(МассивОтметок, "Отметка");
    
  3. 🔹 Значения, зависящие от других колонок, — цикл по строкам (подробно ниже, в разделе о вычисляемых колонках).

Обратный метод ВыгрузитьКолонку("Имя") возвращает массив значений колонки. Связка «выгрузить → обработать массив → загрузить» удобна, когда колонку надо пересчитать по сложному правилу.

Имя колонки задано строкой

Если имя колонки приходит из настроек или параметра, обращайтесь к значению через квадратные скобки: Строка[ИмяКолонки]. Обращение через точку Строка.ИмяКолонки тут не сработает — платформа будет искать колонку с именем «ИмяКолонки».

ИмяКолонки = "Остаток_" + Формат(НомерСклада, "ЧГ=0");
ТЗ.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"));

Для Каждого Строка Из ТЗ Цикл
    Строка[ИмяКолонки] = 0;
КонецЦикла;

Формат(..., "ЧГ=0") убирает разделитель групп разрядов. Без него для числа 1000 получится «1 000» с неразрывным пробелом — а такое имя колонки недопустимо.

Колонка таблицы значений на управляемой форме

На форме таблица значений хранится не как ТаблицаЗначений, а как реквизит формы с типом «ТаблицаЗначений». Колонки такого реквизита задаются отдельно — либо в конфигураторе, либо программно на сервере.

Через редактор формы в конфигураторе

  1. Откройте форму и перейдите на вкладку реквизитов (правая верхняя панель редактора формы).
  2. Добавьте реквизит и в его свойствах выберите тип ТаблицаЗначений.
  3. Выделите этот реквизит и в командной панели над списком реквизитов выберите команду добавления колонки — она появляется, когда выделен реквизит-таблица.
  4. Задайте колонке имя, тип и заголовок в палитре свойств.
  5. Перетащите реквизит в дерево элементов формы — получится элемент «Таблица», в котором колонки станут полями.

Если реквизит-таблица уже выведен на форму, а колонку вы добавили позже, перетащите и её в элемент таблицы. Иначе колонка будет в данных, но на экране её не увидят.

Программно на сервере

Когда состав колонок известен только во время работы (например, по числу складов), реквизит формы меняют методом ИзменитьРеквизиты(), а потом создают поле в элементе таблицы. Оба действия выполняются на сервере.

&НаСервере
Процедура ДобавитьКолонкуНаСервере(ИмяКолонки, Заголовок)

    Добавляемые = Новый Массив;
    Добавляемые.Добавить(Новый РеквизитФормы(ИмяКолонки,
        Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)),
        "ТаблицаДанных", Заголовок));
    ИзменитьРеквизиты(Добавляемые);

    Поле = Элементы.Добавить("ТаблицаДанных" + ИмяКолонки, Тип("ПолеФормы"), Элементы.ТаблицаДанных);
    Поле.Вид = ВидПоляФормы.ПолеВвода;
    Поле.ПутьКДанным = "ТаблицаДанных." + ИмяКолонки;

КонецПроцедуры

Третий параметр РеквизитФормы — путь к реквизиту-таблице. Именно он делает новый реквизит колонкой, а не самостоятельным реквизитом формы.

В тонком клиенте тип ТаблицаЗначений недоступен. На клиенте реквизит-таблица — это коллекция данных формы. Чтобы поработать с ней как с обычной ТЗ, на сервере вызовите РеквизитФормыВЗначение("ТаблицаДанных"), а результат верните методом ЗначениеВРеквизитФормы().

Тип колонки: как задать ОписаниеТипов и квалификаторы

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

Конструктор ОписаниеТипов принимает тип и квалификаторы, причём у каждого квалификатора своё место в списке параметров. Отсюда лишние запятые в примерах.

Что нужноКак записать
Число 15 знаков, 2 после запятойНовый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2))
Строка до 100 символовНовый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100))
Только дата, без времениНовый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата))
БулевоНовый ОписаниеТипов("Булево")
Ссылка на справочникНовый ОписаниеТипов("СправочникСсылка.Контрагенты")
Составной типНовый ОписаниеТипов("Число, Строка")

Нюансы, на которых спотыкаются:

  • 🔸 Квалификатор строки без длины (или с длиной 0) даёт строку неограниченной длины. В запросе по такой колонке нельзя группировать и сравнивать — задайте конкретную длину.
  • 🔸 При записи значения в типизированную колонку платформа приводит его к типу колонки. Значение неподходящего типа молча заменяется приведённым — ошибки не будет, поэтому проблема всплывает позже, в итогах или отчёте.
  • 🔸 Тип уже созданной колонки поменять нельзя: свойство ТипЗначения доступно только для чтения. Нужен другой тип — добавьте новую колонку, перенесите значения через ВыгрузитьКолонку / ЗагрузитьКолонку и удалите старую.
  • 🔸 Имя колонки менять можно: свойство Имя доступно на запись.
// Замена типа колонки "Код" со строки на число
Значения = ТЗ.ВыгрузитьКолонку("Код");
Для Индекс = 0 По Значения.ВГраница() Цикл
    Попытка
        Значения[Индекс] = Число(Значения[Индекс]);
    Исключение
        Значения[Индекс] = 0; // строка не является числом
    КонецПопытки;
КонецЦикла;

ТЗ.Колонки.Удалить(ТЗ.Колонки.Найти("Код"));
ТЗ.Колонки.Добавить("Код", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 0)));
ТЗ.ЗагрузитьКолонку(Значения, "Код");

Строки переводятся в число явно, функцией Число(). Так вы сами решаете, что делать со значениями вроде «А-15», а не полагаетесь на автоматическое приведение.

Вычисляемые колонки: сумма, признак, группировка

Самый частый сценарий: в таблице есть количество и цена, нужна сумма. Добавляем колонку и заполняем её в цикле:

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

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

Проверка на числах: 3 штуки по 199,90 дают 599,70 — округление до копеек здесь ничего не меняет, но при цене с тремя знаками после запятой оно уже нужно.

Посчитать прямо в запросе

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

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

Таблица и поля здесь даны для примера — подставьте свой объект метаданных.

Колонка-итог через Свернуть

Когда нужна не построчная величина, а сумма по группам, отдельная колонка не нужна. Метод Свернуть() группирует строки и суммирует указанные колонки:

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

Колонки, не попавшие ни в один из двух параметров, после свёртки удаляются. Если какая-то колонка нужна дальше, включите её в группировочные.

Колонки в больших таблицах: как не замедлить обработку

На таблице в сотни строк разница между подходами незаметна. На десятках и сотнях тысяч строк — заметна. Что помогает:

  • ⚡ Добавляйте колонки до заполнения строк. Таблица, в которую сразу заложена вся структура, проще в сопровождении, и код заполнения пишется одним проходом.
  • ⚡ Один цикл вместо нескольких. Если надо рассчитать три новые колонки, считайте все три в одном Для Каждого, а не тремя проходами.
  • ⚡ Колонку ищите один раз. Колонки.Найти() внутри цикла по строкам — лишняя работа на каждой итерации. Найдите колонку до цикла.
  • ⚡ Пересчёт — в запросе. Арифметика и условия (ВЫБОР КОГДА) на стороне СУБД обычно работают быстрее цикла по ТЗ.
  • ⚡ Лишние колонки — долой. Если таблица передаётся с сервера на клиент или сохраняется, удалите служебные колонки или возьмите копию только с нужными: ТЗ.Скопировать(, "Номенклатура, Сумма").
  • ⚡ Индекс — по колонке поиска. Если по новой колонке будете часто искать через НайтиСтроки(), добавьте индекс: ТЗ.Индексы.Добавить("Отметка").

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

Частые ошибки при добавлении колонок в ТЗ

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

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

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

Можно ли добавить колонку в табличную часть документа так же, как в ТЗ?
Нет. Реквизиты табличной части задаются в конфигураторе, в метаданных объекта. Программно можно выгрузить табличную часть в ТЗ методом Выгрузить() и уже в неё добавить колонку.
Как удалить колонку из таблицы значений?
Методом ТЗ.Колонки.Удалить(Колонка). Колонку удобно получить через ТЗ.Колонки.Найти(“Имя”). Значения в строках удаляются вместе с ней.
Как узнать, сколько колонок в ТЗ, и перебрать их?
Количество возвращает ТЗ.Колонки.Количество(). Перебор: Для Каждого Колонка Из ТЗ.Колонки Цикл — у каждой колонки доступны Имя, Заголовок и ТипЗначения.
Почему в колонке без типа сортировка работает странно?
В нетипизированной колонке могут лежать значения разных типов: числа, строки, Неопределено. Платформа сравнивает их по своим правилам, и порядок выходит неожиданным. Задайте тип при создании колонки.
Работает ли ТаблицаЗначений на тонком клиенте?
Нет, объект доступен на сервере и в толстом клиенте. На форме используйте реквизит типа ТаблицаЗначений, а для полноценной работы переводите его на сервере в ТЗ через РеквизитФормыВЗначение().