Добавление колонок в таблицу значений: методы и примеры кода
Содержание
Колонку в таблицу значений добавляют одной строкой: Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число")). Коллекция Колонки есть у каждой таблицы значений, и именно через её методы Добавить, Вставить, Удалить и Сдвинуть вы меняете набор полей — создаёте их на лету, задаёте тип и порядок.
Задача возникает постоянно: собираете таблицу в обработке или отчёте, и по ходу выясняется, что нужно ещё одно поле — расчётная сумма, флаг, колонка под каждый месяц периода. Ниже — все рабочие способы с проверенным кодом: от минимального вызова до динамического создания десятков колонок и заполнения значений без переспама по строкам.
Весь код написан для встроенного языка 1С:Предприятие 8.3 и работает одинаково на тонком и толстом клиенте, в общих модулях и модулях объектов.
Метод Добавить: минимальный вызов и его параметры
Полная сигнатура такая:
Таблица.Колонки.Добавить(<Имя>, <Тип>, <Заголовок>, <Ширина>)
Обязателен только первый параметр — имя. Остальные можно не передавать:
Таблица = Новый ТаблицаЗначений;
// минимум — только имя, колонка принимает любой тип
Таблица.Колонки.Добавить("Комментарий");
// имя и тип
Таблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
// имя, тип, заголовок, ширина — для вывода на форму
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"), "Сумма, руб.", 12);
Разберём параметры:
- 🏷️ Имя — программный идентификатор колонки. По нему вы обращаетесь к значению в коде:
Строка.Сумма. Правила как у имён переменных: буквы, цифры и подчёркивание, без пробелов, не начинается с цифры. - 🔤 Тип — объект
ОписаниеТипов. Если не передать, колонка будет универсальной и примет значение любого типа. - 📝 Заголовок — текст, который видит пользователь, когда таблица выведена на форму или в табличный документ. Здесь пробелы и знаки допустимы.
- 📐 Ширина — ширина колонки в символах при выводе. На логику кода не влияет.
Метод Добавить возвращает созданный объект — КолонкаТаблицыЗначений. Это удобно, когда свойств много:
НоваяКолонка = Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
НоваяКолонка.Заголовок = "Кол-во, шт";
НоваяКолонка.Ширина = 8;
У объекта колонки доступны для чтения и записи Имя, Заголовок, Тип, Ширина. Значит, уже созданную колонку можно позже переименовать или сменить ей заголовок, не пересоздавая.
Какой тип задать через ОписаниеТипов
Тип колонки описывает объект ОписаниеТипов. В простом случае достаточно строки с названием типа:
Новый ОписаниеТипов("Число")
Новый ОписаниеТипов("Строка")
Новый ОписаниеТипов("Дата")
Новый ОписаниеТипов("Булево")
Новый ОписаниеТипов("СправочникСсылка.Контрагенты")
Можно разрешить несколько типов сразу — перечислите их через запятую:
Таблица.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число, Строка"));
Для чисел, строк и дат стоит задавать квалификаторы — они ограничивают разрядность и длину. Это не формальность: от квалификаторов зависит, как значение ляжет в систему компоновки данных и как округлится при присваивании.
// число: 15 знаков всего, 2 после запятой
Таблица.Колонки.Добавить("Сумма",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
// строка ограниченной длины 150 символов
Таблица.Колонки.Добавить("Наименование",
Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
Обратите внимание на позицию квалификаторов в конструкторе ОписаниеТипов: сначала строка типов, затем КвалификаторыЧисла, КвалификаторыСтроки, КвалификаторыДаты. Поэтому для строки квалификатор идёт третьим параметром, а второй пропускается запятой.
Если тип не задать вовсе, колонка остаётся универсальной. Для разовых буферных таблиц это нормально, но для таблиц, которые пойдут в СКД или в сравнение значений, тип указывать нужно — иначе получите неожиданные результаты сортировки и группировки.
Когда тип колонки должен в точности повторять реквизит справочника или документа, не выписывайте его вручную — возьмите готовое описание из метаданных:
ТипАртикула = Метаданные.Справочники.Номенклатура.Реквизиты.Артикул.Тип;
Таблица.Колонки.Добавить("Артикул", ТипАртикула);
Колонка получит ровно тот тип и те квалификаторы длины, что заданы у реквизита, и никогда не разойдётся с ним при изменении конфигурации. Этот же приём работает со стандартными реквизитами — например, тип ссылки берётся из ...СтандартныеРеквизиты.Ссылка.Тип.
Куда встанет колонка и как поменять порядок
Добавить всегда дописывает колонку в конец. Если нужна строго определённая позиция — используйте Вставить, первый параметр здесь индекс (отсчёт с нуля):
// поставить "Номер строки" самой первой колонкой
Таблица.Колонки.Вставить(0, "НомерСтроки", Новый ОписаниеТипов("Число"), "№");
Остальные параметры Вставить те же, что у Добавить: имя, тип, заголовок, ширина.
Уже существующую колонку можно подвинуть методом Сдвинуть. Второй параметр — смещение: отрицательное влево, положительное вправо.
Колонка = Таблица.Колонки.Найти("Сумма");
Таблица.Колонки.Сдвинуть(Колонка, -1); // на одну позицию левее
Узнать текущий номер колонки помогает Индекс, а общее число — Количество:
Позиция = Таблица.Колонки.Индекс(Таблица.Колонки.Найти("Сумма"));
Всего = Таблица.Колонки.Количество();
Метод Найти возвращает либо объект колонки, либо Неопределено, если такой нет. Это главный способ проверить существование колонки перед любыми операциями.
Лишнюю колонку убирают методом Удалить — ему передают имя, индекс или сам объект колонки:
Таблица.Колонки.Удалить("Черновик");
Данные удалённой колонки исчезают во всех строках вместе с ней, отдельно чистить строки не нужно. Если же таблицу надо пересобрать с нуля, строки убирает Таблица.Очистить(), после чего можно заново описать нужный набор колонок.
Создание колонок по условию и списком
Самый частый сценарий динамики — набор колонок заранее неизвестен: он приходит из массива имён, из запроса или зависит от периода отчёта. Шаблон один и тот же — перебираем источник и добавляем колонки в цикле, проверяя, что имя ещё не занято:
ИменаМесяцев = СтрРазделить("Январь,Февраль,Март,Апрель", ",");
Для Каждого Месяц Из ИменаМесяцев Цикл
Если Таблица.Колонки.Найти(Месяц) = Неопределено Тогда
Таблица.Колонки.Добавить(Месяц, Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)), Месяц);
КонецЕсли;
КонецЦикла;
Проверка через Найти критична: повторное добавление колонки с занятым именем вызывает ошибку и обрывает выполнение. В динамике, где имена приходят из данных, дубли почти неизбежны, поэтому Если Найти = Неопределено ставьте всегда.
Колонки по условию — тот же приём, только добавление под Если:
Если ВыводитьНДС Тогда
Таблица.Колонки.Добавить("НДС", Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)), "НДС");
Таблица.Колонки.Добавить("СуммаСНДС", Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)), "Всего с НДС");
КонецЕсли;
Когда имена колонок берутся из результата запроса (например, список складов или статей затрат), перебирайте выборку и так же добавляйте поля. Имя при этом лучше делать техническим (Склад_» + Код), а человекочитаемое название класть в Заголовок, чтобы не упереться в правила идентификаторов.
Чем заполнить новую колонку
Когда колонку добавляют в уже заполненную таблицу, значения проставляются автоматически по типу:
| Тип колонки | Значение в существующих строках |
|---|---|
| Число | 0 |
| Строка | пустая строка "" |
| Булево | Ложь |
| Дата | пустая дата |
| Ссылка | пустая ссылка |
| Тип не задан | Неопределено |
Дальше значения заполняют одним из двух способов. Обход строк — когда значение считается по другим колонкам:
Для Каждого Строка Из Таблица Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
Если же готовый набор значений лежит в массиве, быстрее загрузить его целиком методом ЗагрузитьКолонку — он разложит элементы массива по строкам в их порядке:
Таблица.ЗагрузитьКолонку(МассивСумм, "Сумма");
Число элементов массива должно совпадать с числом строк таблицы, иначе часть строк останется с пустым значением, а лишние элементы просто отбросятся. Обратная операция — ВыгрузитьКолонку("Сумма") — вернёт массив всех значений колонки.
Что учесть на таблицах в тысячи строк
Само добавление колонки от размера таблицы почти не зависит — платформа инициализирует новое поле значением по умолчанию быстро даже на десятках тысяч строк. Тормозит обычно не вставка колонки, а то, что делают после неё.
Главная ловушка — поиск строк в цикле. Если после добавления колонки вы в цикле ищете строки методом Найти или НайтиСтроки, на большой таблице это даёт квадратичную нагрузку. Решение — заранее построить индекс по колонкам, по которым ищете:
Таблица.Индексы.Добавить("Номенклатура");
Таблица.Индексы.Добавить("Склад, Номенклатура");
После этого НайтиСтроки по проиндексированным колонкам работает на порядки быстрее.
Ещё пара практичных приёмов на объёмах:
- 🧮 заполняйте расчётную колонку одним проходом
Для Каждого, а не через повторныйНайтипо той же таблице; - 📦 если структура колонок известна заранее, объявляйте все колонки до загрузки строк — тогда платформа не переинициализирует значения по мере добавления полей;
- 🧩 для переноса структуры в другую таблицу есть
СкопироватьКолонки()— вернёт пустую таблицу с тем же набором колонок, строки перебирать не нужно.
Собираем таблицу под отчёт: пример целиком
Соберём живой пример — таблицу для простого отчёта по продажам. Сначала объявляем базовые колонки, затем добавляем колонки-месяцы по периоду, заполняем данные и в конце дописываем расчётную колонку «Итого». Так все приёмы из статьи работают вместе.
// 1. базовая структура
Продажи = Новый ТаблицаЗначений;
Продажи.Колонки.Добавить("Номенклатура",
Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Товар", 30);
// 2. динамически — колонка под каждый месяц
ИменаМесяцев = СтрРазделить("Январь,Февраль,Март", ",");
Для Каждого Месяц Из ИменаМесяцев Цикл
Если Продажи.Колонки.Найти(Месяц) = Неопределено Тогда
Продажи.Колонки.Добавить(Месяц, Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)), Месяц, 10);
КонецЕсли;
КонецЦикла;
// 3. заполнили строки (здесь — учебными данными)
Строка = Продажи.Добавить();
Строка.Номенклатура = Товар;
Строка.Январь = 1000;
Строка.Февраль = 1500;
Строка.Март = 1200;
// 4. расчётная колонка поверх уже заполненной таблицы
Продажи.Колонки.Добавить("Итого", Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)), "Итого за квартал", 12);
Для Каждого Строка Из Продажи Цикл
Строка.Итого = Строка.Январь + Строка.Февраль + Строка.Март;
КонецЦикла;
Ключевой момент — порядок. Колонку «Итого» добавляем после загрузки строк: во всех строках она сразу получит значение 0, а цикл пересчитает его по месяцам. Если бы месяцев было двенадцать, их имена так же пришли бы списком или из запроса, а не писались руками.
Тот же подход годится для кросс-таблиц любого вида: строки — один разрез (товары, подразделения), а динамические колонки — второй (периоды, склады). Набор колонок при этом рождается из данных, а не фиксируется в коде заранее.
Ошибки, на которых спотыкаются чаще всего
Отдельно про имя и заголовок — это разные вещи, и путаница между ними порождает половину вопросов. Имя нужно коду и правилам идентификаторов подчиняется строго. Заголовок нужен пользователю и может быть любым текстом. Задавайте оба: по имени обращаетесь в коде, заголовок видит человек.
Частые вопросы
Можно ли добавить колонку, если таблица уже заполнена строками?
Чем отличается Имя колонки от Заголовка?
Строка.Сумма), подчиняется правилам имён переменных. Заголовок — текст для показа на форме и в табличном документе, в нём допустимы пробелы и знаки. Это независимые свойства.Как проверить, есть ли уже такая колонка?
Колонки.Найти(Имя). Он вернёт объект колонки, если она есть, или Неопределено, если нет. На этой проверке строят безопасное добавление в циклах.Как переименовать колонку, не теряя данные?
Имя у объекта колонки: Таблица.Колонки.Найти("Старое").Имя = "Новое". Данные в строках сохранятся, меняется только идентификатор.Как скопировать набор колонок в другую таблицу?
Таблица.СкопироватьКолонки() вернёт новую пустую таблицу с тем же составом и типами колонок. Если нужны и колонки, и строки — используйте Таблица.Скопировать().