К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как изменить тип значения колонки таблицы значений в 1С

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

Таблица значений в 1С — это несохраняемый объект, структура колонок которого задаётся при добавлении колонки методом ТаблицаЗначений.Колонки.Добавить(). Уже созданной колонке нельзя просто присвоить новый тип: свойство ТипЗначения у объекта «КолонкаТаблицыЗначений» доступно только для чтения. Поэтому изменение типа всегда сводится к одному из обходных приёмов — созданию новой колонки с нужным типом, переносу данных или полному пересозданию таблицы.

Задача возникает регулярно: колонка создана как строка, а нужно хранить числа для сортировки и итогов; колонка с типом «Строка» неограниченной длины не подходит для помещения таблицы в запрос; при загрузке из Excel все значения пришли строками, а дальше требуется типизированная обработка. Ниже разобраны рабочие способы, их ограничения и способы проверки результата.

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

Коллекция ТаблицаЗначений.Колонки хранит объекты типа «КолонкаТаблицыЗначений». У каждой колонки есть свойства Имя, ТипЗначения, Заголовок, Ширина. Из них программно изменяемы имя, заголовок и ширина, а ТипЗначения — свойство только для чтения. Попытка присвоить ему новое значение вызовет ошибку исполнения.

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

Важно понимать и обратное: тип отдельной ячейки ограничен типом колонки. Если колонка объявлена как «Строка(10)», присвоить ей число можно (оно будет приведено к строке), но получить из ячейки число без явного преобразования не получится.

Способ 1. Добавление новой колонки и перенос данных

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

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

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

// 2. Перенос с преобразованием
Для Каждого СтрокаТЗ Из ТЗ Цикл
    СтрокаТЗ.СуммаНов = Число(СтрЗаменить(СтрокаТЗ.Сумма, " ", ""));
КонецЦикла;

// 3. Удаляем старую, переименовываем новую
ИндексСтарой = ТЗ.Колонки.Индекс(ТЗ.Колонки.Найти("Сумма"));
ТЗ.Колонки.Удалить("Сумма");
ТЗ.Колонки.СуммаНов.Имя = "Сумма";
ТЗ.Колонки.Сдвинуть("Сумма", ИндексСтарой - ТЗ.Колонки.Индекс(ТЗ.Колонки.Сумма));

Обратите внимание на два момента. Во-первых, функция Число() вызовет исключение, если строка содержит непреобразуемые символы (буквы, «р.», неразрывные пробелы). Перед преобразованием строку стоит очистить: убрать пробелы, заменить запятую на точку, отфильтровать лишние символы. Во-вторых, после удаления старой колонки позиция новой меняется — если порядок колонок важен (например, таблица выводится на форму), используйте Колонки.Сдвинуть().

Порядок действий при замене типа колонки
  1. 1
    Добавьте новую колонку с требуемым ОписаниеТипов рядом со старой
  2. 2
    В цикле по строкам перенесите значения с явным преобразованием типа
  3. 3
    Проверьте, что преобразование не дало потерь (пустые или нулевые значения там, где были данные)
  4. 4
    Удалите старую колонку методом Колонки.Удалить()
  5. 5
    Переименуйте новую колонку в исходное имя и при необходимости сдвиньте её на прежнюю позицию

Способ 2. Пересоздание таблицы целиком

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

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

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

Сравнение подходов

Новая колонка + перенос

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

Пересоздание таблицы

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

Составной тип с самого начала

Профилактика проблемы: колонка объявляется с несколькими типами (например, Число и Строка), и смена типа вообще не требуется. Усложняет сортировку и передачу в запрос.

Способ 3. Типизация через запрос и функции преобразования

Когда таблица значений дальше участвует в запросе (помещается во временную таблицу), типизацию можно выполнить прямо в запросе. В тексте запроса доступны функции ВЫРАЗИТЬ(... КАК ЧИСЛО(15,2)), КАК СТРОКА(100), КАК ДАТА, а также оператор ВЫБОР КОГДА ... ТОГДА для условного преобразования.

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

У этого способа есть важное ограничение: если строка не может быть приведена к числу, результатом будет NULL, а не ошибка. Это удобно для фильтрации «мусорных» значений, но требует проверки на NULL при дальнейшей обработке.

bsl
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТЗ", ТаблицаИзФайла);
Запрос.Текст =
"ВЫБРАТЬ
|   ВЫРАЗИТЬ(ТЗ.Код КАК СТРОКА(9)) КАК Код,
|   ВЫРАЗИТЬ(ТЗ.Сумма КАК ЧИСЛО(15, 2)) КАК Сумма,
|   ВЫРАЗИТЬ(ТЗ.ДатаСтр КАК ДАТА) КАК ДатаДок
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ &ТЗ КАК ТЗ
|;
|ВЫБРАТЬ * ИЗ ВТ_Данные";
ТипизированнаяТЗ = Запрос.Выполнить().Выгрузить();

Типичные преобразования и их подводные камни

Строка → Число. Главные проблемы — неразрывные пробелы в качестве разделителя разрядов, запятая вместо точки, валютные символы. Перед Число() выполните СтрЗаменить по всем встречающимся разделителям. Помните о квалификаторах: Число(10,0) обрежет дробную часть при записи в ячейку.

Строка → Дата. Функция Дата() принимает строку строго в формате «ГГГГММДДччммсс» (время можно опустить). Даты вида «31.12.2023» нужно предварительно разобрать через СтрРазделить и собрать в канонический формат, либо использовать ВЫРАЗИТЬ в запросе с предварительной нормализацией.

Число → Строка. Платформа применяет региональные настройки форматирования, поэтому в строку могут попасть разделители групп разрядов. Для контролируемого результата используйте Формат(Значение, "ЧГ="), чтобы отключить группировку разрядов.

Сужение строки. Перевод колонки из «Строка(200)» в «Строка(50)» молча обрезает значения длиннее 50 символов при записи. Если данные ценны, сначала проверьте максимальную фактическую длину значений в колонке.

Типичные ошибки
01
Попытка присвоить значение свойству Колонка.ТипЗначения — свойство только для чтения, возникает ошибка исполнения
02
Преобразование Число() без очистки строки от пробелов и разделителей — исключение на первом же 'грязном' значении
03
Сужение строковой колонки без проверки длин — часть данных обрезается без предупреждения
04
Потеря позиции колонки после удаления старой — таблица на форме отображается с другим порядком колонок
05
Использование ВЫРАЗИТЬ в запросе без проверки на NULL — непреобразованные значения молча превращаются в NULL

Ограничения: составные типы, запросы и длина строк

Колонка может иметь составной тип — например, Новый ОписаниеТипов("Число,Строка"). Это законный способ избежать смены типа, но цена решения — неоднозначность при сортировке (строки и числа сравниваются по особым правилам), невозможность корректной свёртки по такой колонке и проблемы при помещении таблицы в запрос: СУБД требует однозначного типа поля.

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

Также учтите: если таблица значений связана с реквизитом формы (например, выведена в табличное поле), добавление и удаление колонок на сервере потребует повторного связывания или обновления отображения. В управляемых формах структуру реквизита типа «ТаблицаЗначений» меняют через ИзменитьРеквизиты(), а не прямыми манипуляциями с колонками данных формы.

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

После переноса данных убедитесь, что тип действительно изменился и данные не пострадали. Минимальная проверка — сравнить количество строк и контрольные итоги до и после. Для числовой колонки сравните сумму старых значений (преобразованных тем же способом) с суммой новой колонки.

Полезно также проверить тип программно: ТЗ.Колонки.Сумма.ТипЗначения.СодержитТип(Тип("Число")) должно вернуть Истина. Для выборочной проверки значений используйте ТипЗнч(ТЗ[0].Сумма) — он покажет фактический тип значения в ячейке.

Контрольные точки

Как проверить результат

Тип колонки в коллекции
Норма

ТипЗначения содержит целевой тип, лишних типов нет

Тревожный признак

Остался старый тип или нежелательный составной тип

Контрольная сумма данных
Норма

Итог по новой колонке совпадает с итогом по преобразованным старым значениям

Тревожный признак

Итог меньше — часть значений не преобразовалась или обрезалась

Пустые значения
Норма

Пусто там, где исходное значение было пустым или нулевым

Тревожный признак

Нули и пустые строки появились там, где были данные

Поведение в запросе
Норма

Таблица помещается в запрос без ошибок, соединения по колонке работают

Тревожный признак

Ошибка о неограниченной длине строки или несовместимости типов

Практические рекомендации

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

Для преобразования строк в числа в цикле используйте безопасную обёртку: попытка преобразования внутри Попытка ... Исключение с записью проблемного значения в журнал или отдельную таблицу ошибок. Так вы не потеряете всю обработку из-за одной некорректной строки.

Если тип колонки приходится менять регулярно в разных местах кода, вынесите операцию в общую функцию вида ИзменитьТипКолонки(ТЗ, ИмяКолонки, НовоеОписаниеТипов). Это уменьшит количество дублирующегося кода и снизит риск забыть переименование или сдвиг колонки.

Частая причина, по которой разработчики ищут способ сменить тип колонки, — загрузка из Excel или CSV, где всё приходит строками. В этом случае эффективнее не менять типы постфактум, а написать функцию преобразования значения по заданному типу и применять её прямо при чтении файла. Таблица сразу получается типизированной, и вся тема замены типов отпадает.
ПЗ
Практическое замечание
Итог

Что важно запомнить

Тип колонки таблицы значений изменить напрямую нельзя — свойство ТипЗначения доступно только для чтения. Рабочие приёмы: новая колонка с нужным ОписаниеТипов и перенос данных, пересоздание таблицы целиком или типизация через ВЫРАЗИТЬ в запросе. Перед удалением старой колонки сохраните копию данных, а после переноса сверьте контрольные итоги.

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

Можно ли изменить тип колонки без потери данных?

Да, если переносить значения в новую колонку с корректным преобразованием. Потери возможны только при сужении типа (обрезание длинных строк, округление чисел) или при непреобразуемых значениях. Сверка контрольных итогов до и после переноса покажет, прошла ли операция без потерь.

Как изменить тип колонки таблицы значений на форме?

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

Почему таблица значений не помещается в запрос?

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

Что делать, если при Число() возникает ошибка преобразования?

Очистите строку перед преобразованием: удалите пробелы (включая неразрывные — символ с кодом 160), замените запятую на точку, уберите валютные обозначения. Оберните преобразование в Попытка/Исключение, чтобы одна некорректная строка не прерывала обработку всей таблицы, и логируйте проблемные значения.

Можно ли сделать колонку, принимающую и числа, и строки?

Да, при добавлении колонки передайте составной тип: Новый ОписаниеТипов("Число,Строка"). Учтите последствия: сортировка по такой колонке даёт неочевидный порядок, свёртка и итоги работают только с числовой частью, а помещение таблицы в запрос может завершиться ошибкой несовместимости типов.

Как изменить тип колонки у дерева значений?

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