Переименование колонки в таблице значений: имя, заголовок и обходные пути

· 9 мин

Содержание

Первая мысль — найти у колонки свойство Имя и присвоить ему новое значение. Не сработает: после создания колонки её имя остаётся прежним. Менять можно только Заголовок — подпись, которую видит пользователь. А если нужно именно новое имя, колонку создают заново и переносят в неё данные.

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

Чем имя колонки отличается от заголовка и синонима

Колонка таблицы значений (объект КолонкаТаблицыЗначений) хранит четыре вещи:

  • Имя — идентификатор для обращения из кода. Только латиница или кириллица, цифры и подчёркивание, без пробелов, не начинается с цифры.
  • Заголовок — произвольная строка для пользователя. Пробелы, знаки, любые слова.
  • ТипЗначения — допустимые типы данных колонки.
  • Ширина — ширина при выводе в таблицу формы.

Колонка создаётся методом Добавить:

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

Третий параметр — заголовок. Если его не передать, при отображении используется имя.

У колонки таблицы значений нет «синонима» в том смысле, в каком он есть у реквизитов объектов метаданных. Синоним — это свойство объекта в конфигураторе (реквизит справочника, документа). Менять его в конфигураторе — одна задача. Переименовывать колонку временной таблицы в коде — другая. Не путайте.

Как поменять заголовок колонки

Это самый простой и самый частый сценарий. Заголовок присваивается напрямую:

ТЗ.Колонки.Сумма.Заголовок = "Сумма с НДС";

Можно обратиться к колонке по имени строкой или через индекс:

ТЗ.Колонки["Сумма"].Заголовок = "Сумма с НДС";
ТЗ.Колонки[1].Заголовок = "Сумма с НДС";

Пройти по всем колонкам и привести заголовки к нужному виду:

Для Каждого Колонка Из ТЗ.Колонки Цикл
    Колонка.Заголовок = СтрЗаменить(Колонка.Имя, "_", " ");
КонецЦикла;

Код в форме использует Имя и ничего не заметит: Строка.Сумма по-прежнему работает. Когда задача звучит как «в таблице должна быть другая подпись», вам нужен именно этот способ.

Если таблица значений привязана к таблице формы, заголовок колонки формы можно задать и отдельно — в свойствах элемента формы. Он перекрывает заголовок колонки самой таблицы значений.

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

Если нужно новое имя (например, поменять Сумма на СуммаБезНДС, потому что дальше код обращается к нему), придётся пройти четыре шага:

  1. Добавить новую колонку с тем же типом.
  2. Скопировать значения из старой колонки.
  3. Удалить старую колонку.
  4. При необходимости вернуть порядок колонок.

Простой вариант — через цикл:

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

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

ТЗ.Колонки.Удалить(Старая);

Быстрее на больших таблицах — выгрузка и загрузка колонки целиком:

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

ВыгрузитьКолонку возвращает массив значений в порядке строк, ЗагрузитьКолонку кладёт их обратно по порядку. На таблице в сто тысяч строк разница с циклом заметна.

Как сохранить позицию колонки

Добавить ставит колонку в конец. Если важен порядок, используйте Вставить с индексом старой колонки:

Индекс = ТЗ.Колонки.Индекс(ТЗ.Колонки.Сумма);
ТЗ.Колонки.Вставить(Индекс, "СуммаБезНДС", ТЗ.Колонки.Сумма.ТипЗначения, "Сумма без НДС");

После вставки старая колонка сдвинется на одну позицию вправо. Скопируйте значения и удалите её.

Что нужно учесть при переносе

ЧтоКак поведёт себя
Тип значенийБерите ТипЗначения старой колонки, иначе потеряете квалификаторы (длину, точность)
ЗначенияКопируются по строкам; при выгрузке массивом порядок сохраняется
Ссылки из кода на старое имяСтанут ошибкой: Поле объекта не обнаружено (Сумма)
Индексы таблицыЕсли заданы индексы по старой колонке, пересоздайте их
Ширина, заголовокНе переносятся сами; задайте при создании

Обратите внимание на третью строку. После удаления колонки каждое Строка.Сумма в коде ниже по стеку вызовов упадёт во время выполнения, а не при проверке синтаксиса. Найдите все обращения поиском по модулю до того, как удалять колонку.

Универсальная процедура переименования

Если переименовывать приходится часто, оформите перенос в одну функцию. Она принимает таблицу, старое и новое имя, сохраняет тип, заголовок и позицию колонки:

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

    Старая = ТЗ.Колонки.Найти(СтароеИмя);
    Если Старая = Неопределено Тогда
        ВызватьИсключение "Колонка не найдена: " + СтароеИмя;
    КонецЕсли;

    Если ТЗ.Колонки.Найти(НовоеИмя) <> Неопределено Тогда
        ВызватьИсключение "Колонка уже существует: " + НовоеИмя;
    КонецЕсли;

    Индекс = ТЗ.Колонки.Индекс(Старая);
    Значения = ТЗ.ВыгрузитьКолонку(Старая);

    ТЗ.Колонки.Вставить(Индекс, НовоеИмя, Старая.ТипЗначения, Старая.Заголовок, Старая.Ширина);
    ТЗ.ЗагрузитьКолонку(Значения, НовоеИмя);
    ТЗ.Колонки.Удалить(Старая);

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

Вызов выглядит так: ПереименоватьКолонку(ТЗ, "Сумма", "СуммаБезНДС");. Новая колонка встаёт на место старой, поэтому порядок в таблице не меняется. Порядок действий в процедуре важен: сначала проверки, потом вставка, загрузка и только в конце удаление.

Переименовать сразу несколько колонок можно через соответствие:

Переименования = Новый Соответствие;
Переименования.Вставить("Сумма", "СуммаБезНДС");
Переименования.Вставить("Кол", "Количество");

Для Каждого Пара Из Переименования Цикл
    ПереименоватьКолонку(ТЗ, Пара.Ключ, Пара.Значение);
КонецЦикла;

Ключ соответствия — старое имя, значение — новое. Если в таблице нет какой-то колонки из списка, процедура упадёт с понятным сообщением; при необходимости добавьте проверку через Найти и пропускайте отсутствующие.

Когда проще создать копию таблицы

Бывает, что колонок много, а поменять нужно только одну. Или таблица приходит снаружи и вы не хотите трогать оригинал. Тогда соберите новую таблицу с нужной структурой и пройдите по строкам:

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

Для Каждого Строка Из Исходная Цикл
    Новая = Результат.Добавить();
    Новая.Товар = Строка.Номенклатура;
    Новая.СуммаБезНДС = Строка.Сумма;
КонецЦикла;

Способ медленнее выгрузки колонки, зато в нём видно всё: можно сразу пересчитать значения. Например, исходная сумма с НДС 20% равна 1 200, а в новой колонке нужна сумма без налога. Формула Строка.Сумма / 1.2 даст 1 000. Такое преобразование при переименовании колонки получается само собой.

Для простого копирования структуры без данных пригодится метод СкопироватьКолонки: ТЗ.СкопироватьКолонки() создаёт пустую таблицу с теми же колонками. Дальше остаётся добавить новую колонку и заполнить её.

Проверка результата после переименования

Прежде чем отдавать таблицу дальше, убедитесь в трёх вещах:

  • старого имени в таблице больше нет: ТЗ.Колонки.Найти("Сумма") = Неопределено;
  • число колонок такое же, как до операции (или на единицу меньше, если колонку просто убирали);
  • значения в новой колонке совпадают: сравните итог по старой и по новой, например ТЗ.Итог("СуммаБезНДС") с суммой, посчитанной до переноса.

Последняя проверка ловит самую неприятную ошибку: когда в цикле затёрли значения или потеряли строки. Если итоги не совпали, смотрите тип колонки. Число с квалификатором, обрезанным до целых, молча округлит копейки.

Перед удалением старой колонки
Выполнено: 0 / 4

Имена колонок при выгрузке результата запроса

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

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

В таблице окажутся колонки Товар и Код. Без КАК платформа сформирует имя по имени поля, а при конфликте добавит числовой суффикс — потому лучше всегда писать псевдонимы явно.

Если запрос уже написан и менять его нельзя, остаётся способ с новой колонкой из предыдущего раздела.

Для объединений действует правило: имена колонок берутся из первого запроса в ОБЪЕДИНИТЬ. Псевдонимы в остальных частях на имя не влияют, важен только порядок полей.

Динамическое создание и переименование колонок в форме

Отдельный случай — реквизит формы с типом ТаблицаЗначений, колонки которого строят программно. Здесь таблица значений отдельно, а колонки формы — отдельно. Они связаны, и менять их через Колонки.Добавить у реквизита нельзя: структуру реквизита формы меняет только метод ИзменитьРеквизиты.

Порядок действий такой:

  1. Собрать массив добавляемых реквизитов (Новый РеквизитФормы) и массив удаляемых имён.
  2. Вызвать ИзменитьРеквизиты(Добавляемые, Удаляемые).
  3. Создать элемент формы для новой колонки через Элементы.Добавить.
  4. Загрузить данные заново.

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

&НаСервере
Процедура ПереименоватьКолонкуНаСервере()
    Данные = РеквизитФормыВЗначение("Таблица");
    Добавляемые = Новый Массив;
    Добавляемые.Добавить(Новый РеквизитФормы("СуммаБезНДС", Новый ОписаниеТипов("Число"), "Таблица"));
    Удаляемые = Новый Массив;
    Удаляемые.Добавить("Таблица.Сумма");
    ИзменитьРеквизиты(Добавляемые, Удаляемые);
    // дальше: убрать старый элемент формы, добавить новый,
    // перенести данные из Данные в реквизит "Таблица"
КонецПроцедуры

Элемент формы, привязанный к удалённому реквизиту, надо убрать самостоятельно (Элементы.Удалить). Иначе форма выдаст ошибку привязки к данным.

Как заголовки колонок попадают в табличный документ

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

Типовой приём — выводить именно заголовок, а если он пуст, то имя:

Для Каждого Колонка Из ТЗ.Колонки Цикл
    Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок);
    // вывести Текст в ячейку шапки области макета
КонецЦикла;

Для вывода в обычную таблицу формы шапка берётся из заголовков автоматически. Для вывода через систему компоновки данных заголовки задаёт схема компоновки, а не колонки исходной таблицы: настройте их в поле Заголовок у выбранных полей.

Поэтому «переименовал колонку, а в отчёте старая подпись» — типичная история. Заголовок в таблице значений поменяли, а отчёт строится по схеме компоновки, где подпись задана отдельно.

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

Присвоили Имя, а ничего не произошло, или вылетела ошибка. Свойство доступно только для чтения. Меняйте Заголовок или создавайте колонку заново.

После удаления колонки падает код. Обращения Строка.СтароеИмя остались в других процедурах. Перед удалением найдите их глобальным поиском по конфигурации.

Новая колонка пуста. Забыли скопировать данные или перенесли их в цикле до добавления колонки. Порядок: добавили колонку → скопировали → удалили старую.

Новое имя недопустимо. Имя с пробелом или с цифры в начале платформа не примет. Используйте СуммаБезНДС, а не Сумма без НДС (это годится для заголовка).

Колонка с таким именем уже есть. Добавить с дублем имени вызовет исключение. Проверяйте заранее:

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

Метод Найти возвращает колонку или Неопределено, исключения не бросает.

Как отладить структуру таблицы

Остановитесь точкой останова после изменений и выведите в окно вычисления выражения ТЗ.Колонки.Количество(). Увидите число колонок. Для списка имён хватит короткого цикла:

Для Каждого Колонка Из ТЗ.Колонки Цикл
    Сообщить(Колонка.Имя + " / " + Колонка.Заголовок);
КонецЦикла;

Так проверяют, что имя и заголовок разошлись именно так, как задумано.

Какой способ выбрать

Что именно нужно изменить?

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

Можно ли присвоить колонке новое имя одной строкой?
Нет. После создания колонки её имя не меняется. Создайте новую колонку и перенесите данные.
Чем заголовок колонки отличается от имени?
Имя нужно коду, заголовок — пользователю. Заголовок можно менять в любой момент, на код он не влияет.
Сохранятся ли данные при удалении колонки?
Значения удаляемой колонки теряются вместе с ней. Сначала выгрузите их в массив или скопируйте в новую колонку.
Как переименовать колонку, если таблица получена из запроса?
Проще всего изменить псевдоним в запросе. Иначе добавьте колонку с новым именем и скопируйте в неё значения.
Что делать, если колонка нужна на форме под другим названием?
Задайте заголовок в свойствах колонки таблицы формы. Имя в данных трогать не нужно.