Смена типа колонки Таблицы Значений: новая колонка вместо правки старой
Содержание
Свойство ТипЗначения у колонки Таблицы Значений доступно только для чтения. Строка Таблица.Колонки.Цена.ТипЗначения = Новый ОписаниеТипов("Число") вызовет ошибку. Тип колонки задаётся в момент создания и дальше не меняется.
Выход один: создать колонку с нужным типом, перенести в неё данные с приведением значений, старую колонку удалить. Ниже разобрано, как это сделать без потери данных, что происходит с «неподходящими» значениями и как не нарваться на тихие ошибки.
Как устроена типизация колонок
Колонку можно добавить двумя способами. Без типа: Таблица.Колонки.Добавить("Сумма"). Тогда в ячейку попадёт значение любого типа: число, строка, дата, ссылка. С типом: Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число")). Тогда платформа сама приводит записываемые значения к этому типу.
Разница заметна сразу:
| Колонка | Что запишем | Что получим в ячейке |
|---|---|---|
| Без типа | строка "15" | строка "15" |
Тип Число | строка "15" | число 15 |
Тип Число | строка "abc" | число 0 |
Тип Строка | число 15 | строка "15" |
Последние две строки — источник большинства бед. Значение, которое не удалось привести, не вызывает исключения. Оно молча превращается в пустое значение типа. Данные потерялись, а ошибки в журнале нет.
Если колонка типизирована, проверяйте результат переноса сами. Платформа не скажет, что вместо суммы в ячейке теперь ноль.
Что ещё важно знать о типах колонок:
- 🔹 Составной тип разрешён:
Новый ОписаниеТипов("Число, Строка"). Тогда допустимы оба типа. - 🔹 Для числа, строки и даты можно задать квалификаторы: разрядность, длину, состав даты. Они влияют на округление и обрезание.
- 🔹 Ссылочные типы (
СправочникСсылка.Номенклатура) приводятся только к ссылкам этого же вида. Строку в ссылку само присвоение не превратит. - 🔹 Тип
Неопределенои пустое описание типов означают «любой тип». Это поведение колонки без типа.
Добавление колонки с нужным типом
Конструктор описания типов принимает имена типов строкой и квалификаторы:
ОписаниеЧисла = Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный));
ОписаниеСтроки = Новый ОписаниеТипов("Строка",,
Новый КвалификаторыСтроки(100));
ОписаниеДаты = Новый ОписаниеТипов("Дата",,,
Новый КвалификаторыДаты(ЧастиДаты.Дата));
Порядок параметров конструктора: типы, квалификаторы числа, квалификаторы строки, квалификаторы даты. Пропущенные параметры оставляйте пустыми запятыми, как в примере.
Колонку с типом добавляют методом Колонки.Добавить с тремя параметрами: имя, описание типов и заголовок:
Таблица.Колонки.Добавить("СуммаЧисло", ОписаниеЧисла, "Сумма");
Имя колонки уникально в таблице и подчиняется правилам идентификаторов: без пробелов и спецсимволов, не начинается с цифры. Для красивого вывода в форме пользуйтесь заголовком, а не именем.
💡 Если типов несколько и нужно собрать описание из готовых, используйте перегрузку с исходным описанием и добавляемыми типами. Так проще дополнить существующий набор, чем перечислять всё заново.
Безопасный алгоритм: от старой колонки к новой
Допустим, в таблице колонка Сумма содержит строки вида "1500", а нужны числа. Порядок действий:
- Создайте новую колонку с временным именем и нужным типом.
- Пройдите по строкам и запишите в неё приведённое значение старой.
- Удалите старую колонку.
- Если важно имя, создайте колонку заново или работайте с новым именем дальше.
Вот код целиком:
ОписаниеЧисла = Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2));
Таблица.Колонки.Добавить("СуммаНов", ОписаниеЧисла);
Для Каждого Строка Из Таблица Цикл
Строка.СуммаНов = ОписаниеЧисла.ПривестиЗначение(Строка.Сумма);
КонецЦикла;
Таблица.Колонки.Удалить("Сумма");
Метод ПривестиЗначение у описания типов делает то же, что платформа сделала бы при записи в типизированную колонку, но вы видите приведение явно и можете подставить собственную логику.
Что нужно сделать до удаления старой колонки:
- ✅ проверить, что все нужные значения попали в новую колонку (например, сравнить суммы по обеим);
- ✅ убедиться, что нигде дальше по коду не используется старое имя;
- ✅ если таблица передаётся в другой метод или на форму, проверить, не привязаны ли к старой колонке поля табличной части формы.
Удаление колонки необратимо. Если исходная таблица нужна ещё раз, сначала сделайте копию: Копия = Таблица.Скопировать();.
Если нужно сохранить исходное имя
Чтобы сохранить исходное имя, делают два прохода. Сначала переносят данные во временную колонку и удаляют оригинал. Затем создают колонку с исходным именем и нужным типом и копируют данные уже из временной. Это лишний цикл, зато имя остаётся прежним:
Таблица.Колонки.Добавить("Врем", ОписаниеЧисла);
Для Каждого Строка Из Таблица Цикл
Строка.Врем = ОписаниеЧисла.ПривестиЗначение(Строка.Сумма);
КонецЦикла;
Таблица.Колонки.Удалить("Сумма");
Таблица.Колонки.Добавить("Сумма", ОписаниеЧисла);
Для Каждого Строка Из Таблица Цикл
Строка.Сумма = Строка.Врем;
КонецЦикла;
Таблица.Колонки.Удалить("Врем");
Минус: колонка Сумма окажется в конце списка колонок, порядок изменится. Если порядок критичен для вывода, при выгрузке указывайте колонки явно, а не полагайтесь на их позицию.
Альтернатива: пересобрать таблицу
Когда меняется тип у нескольких колонок сразу, проще создать вторую таблицу и заполнить её. Колонки с нужными типами вы объявляете сами, потом одним циклом переносите строки:
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Наименование", ОписаниеСтроки);
Результат.Колонки.Добавить("Сумма", ОписаниеЧисла);
Результат.Колонки.Добавить("Дата", ОписаниеДаты);
Для Каждого Строка Из Таблица Цикл
Нов = Результат.Добавить();
Нов.Наименование = ОписаниеСтроки.ПривестиЗначение(Строка.Наименование);
Нов.Сумма = ОписаниеЧисла.ПривестиЗначение(Строка.Сумма);
Нов.Дата = ОписаниеДаты.ПривестиЗначение(Строка.Дата);
КонецЦикла;
Порядок и имена колонок вы контролируете полностью, лишних временных колонок нет. Для больших таблиц разницы в скорости почти нет: основная нагрузка — сам цикл по строкам.
Работа с колонкой без типа
Колонки без типа чаще всего получаются, когда таблица строится из результата запроса с «Выразить» без указания типа или из внешних данных, либо когда разработчик просто не задал тип. Значения в них разнородные: у одной строки число, у другой строка, у третьей пусто.
Перед приведением посмотрите, что там лежит:
Типы = Новый Соответствие;
Для Каждого Строка Из Таблица Цикл
Тип = ТипЗнч(Строка.Значение);
Типы.Вставить(Тип, Истина);
КонецЦикла;
Для Каждого Пара Из Типы Цикл
Сообщить(Строка(Пара.Ключ));
КонецЦикла;
Так вы увидите реальный набор типов. Дальше решение по обстоятельствам:
- 📌 если нужны только числа, а в данных есть и строки с текстом, решите заранее, что делать с текстом: игнорировать, считать нулём или вынести в отдельный список ошибок;
- 📌 пустая строка
""при приведении к числу даст 0, при приведении к дате — пустую дату01.01.0001; - 📌
НеопределеноиNULLпри приведении превращаются в пустое значение типа.
Если нужно не потерять «плохие» строки, приводите вручную и собирайте проблемные в отдельную таблицу:
Для Каждого Строка Из Таблица Цикл
Приведено = ОписаниеЧисла.ПривестиЗначение(Строка.Значение);
Если Приведено = 0 И Строка.Значение <> 0 Тогда
// значение не число: запоминаем номер строки
Ошибки.Добавить(Таблица.Индекс(Строка) + 1);
КонецЕсли;
Строка.Число = Приведено;
КонецЦикла;
Здесь Ошибки — заранее созданный список значений. Условие «приведено 0, а исходное не 0» ловит именно потерянные значения, а честные нули пропускает.
ОписаниеТипов для сложных случаев
Часть задач простым "Число" не решается. Вот что встречается на практике.
Составной тип. Колонка должна принимать и число, и строку (например, «код» бывает цифровым и буквенным):
Описание = Новый ОписаниеТипов("Число, Строка");
Но приведение к составному типу ничего не меняет: значение подходящего типа остаётся как есть. Если вам нужно привести всё к единому виду, берите один тип.
Ссылочный тип по имени. Описание типов можно собрать строкой: Новый ОписаниеТипов("СправочникСсылка.Контрагенты"). Для ссылки значение приведётся, только если оно уже ссылка этого вида. Строку с наименованием в ссылку неявно не превратить: ищите элемент запросом или методом НайтиПоНаименованию и записывайте найденную ссылку.
Квалификаторы. Если нужно, чтобы число имело два знака после запятой, а строка обрезалась до 50 символов, задайте их в описании. Помните: длинная строка при записи в колонку с ограниченной длиной обрезается без предупреждения.
Расширение существующего описания. Допустим, у колонки уже есть тип и нужно получить расширенное описание «старое плюс ещё один тип». Берите свойство ТипЗначения существующей колонки как исходное:
Старое = Таблица.Колонки.Сумма.ТипЗначения;
Новое = Новый ОписаниеТипов(Старое, "Строка");
Это не меняет старую колонку, а даёт описание для новой.
| Задача | Подход |
|---|---|
| Строка → число | ПривестиЗначение, затем проверка на потерю |
| Число → строка | приведение; для формата используйте Формат() |
| Строка → дата | приведение работает не для любых форматов; сложные форматы разбирайте вручную |
| Строка → ссылка | запрос или поиск по реквизиту, не приведение |
| Любой → составной | описание из нескольких типов, значение не меняется |
Для числа в строку с нужным форматом (разделители, нули) приведения мало: оно даёт стандартное представление. Применяйте Формат(Число, "ЧГ=0") или СтрШаблон.
Задать тип на входе: запрос и копирование
Самый дешёвый способ «сменить» тип — не получать лишний тип вообще. Если таблица строится запросом, приводите поле прямо в тексте запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Данные.Сумма КАК ЧИСЛО(15, 2)) КАК Сумма,
| ВЫРАЗИТЬ(Данные.Описание КАК СТРОКА(100)) КАК Описание
|ИЗ
| ВТ_Данные КАК Данные";
Таблица = Запрос.Выполнить().Выгрузить();
Колонки результата получат типы из выражения ВЫРАЗИТЬ. Переносить данные потом не придётся. Для поля, которое в запросе приходит составным или нетипизированным (например, из объединения разных источников), это обычно единственное разумное место для приведения.
Если таблица уже есть, а менять нужно не тип, а состав колонок, помогает Скопировать. Метод создаёт новую таблицу только с перечисленными колонками, типы остаются прежними:
Узкая = Таблица.Скопировать(, "Наименование, Сумма");
Первый параметр — отбор строк (его можно пропустить), второй — список колонок через запятую. После этого к Узкая можно добавить колонки с нужными типами и заполнить их по алгоритму выше. Так вы не тянете за собой лишние колонки и не удаляете их по одной.
Когда запрос и копирование не подходят, остаётся ручной перенос. Он описан выше и работает в любой версии платформы.
Типичные ошибки при смене типа
Здесь собрано то, на чём спотыкаются чаще всего, без повторения шагов выше.
- ❌ Попытка присвоить
ТипЗначениясуществующей колонки. Получите ошибку записи в свойство, доступное только для чтения. Решение — новая колонка. - ❌ Удаление колонки внутри цикла по строкам, использующего эту колонку. Сначала завершите перенос, потом удаляйте.
- ❌ Обращение к удалённой колонке. Метод
Удалитьубирает колонку вместе с данными, любое последующееСтрока.Суммадаст ошибку поля объекта. - ❌ Склейка числа и строки через
+."Итого: " + Суммане сработает, если Сумма число. ИспользуйтеСтрока(Сумма)илиФормат. - ❌ Доверие к приведению. Нули и пустые даты после переноса часто означают потерянные данные, а не настоящие нули.
- ❌ Смена типа на форме. Если таблица значений привязана к реквизиту формы типа
ТаблицаЗначений, колонки реквизита формы так просто не поменять: изменяют реквизиты черезИзменитьРеквизитына клиенте формы, а данные переносят отдельно.
Проверка после операции занимает пару минут и спасает от «молчаливых» ошибок:
Частые вопросы
Можно ли поменять тип колонки без создания новой?
ТипЗначения у существующей колонки только для чтения. Создавайте колонку с нужным типом и переносите данные.