Смена типа данных колонки в ТаблицеЗначений: рабочие способы

· 9 мин

Содержание

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

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

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

Почему тип колонки не меняется и когда это мешает

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

Менять тип приходится в нескольких типичных ситуациях:

  • 📥 Данные загрузили из внешнего файла или табличного документа, и все колонки получились строковыми, а нужны числа и даты.
  • 🔁 Колонку создали с типом Число с одним знаком после запятой, а сумма теперь требует двух.
  • 🧩 Таблица формируется запросом, и тип колонки определился по первому набору данных, не по задуманной схеме.
  • 🛠 В обработке или отчёте поменялась логика, и вместо ссылки на справочник колонка должна хранить строку.

Во всех случаях логика одна: нужен новый контейнер нужного типа, а старые значения надо переложить через приведение.

Как посмотреть текущую структуру таблицы

Прежде чем что-то менять, посмотрите, какие колонки есть и какого они типа. Не угадывайте по данным: колонка может содержать только числа, но иметь составной тип.

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

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

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

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

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

В отладчике откройте окно вычисления выражения и посмотрите ТаблицаДанных.Колонки. Так видно структуру живой таблицы без правки кода и без вывода сообщений.

Новая таблица с нужной структурой: способ без побочных эффектов

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

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

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

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

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

Что здесь важно:

  1. Остальные колонки копируются с прежним типом, поэтому таблица меняется точечно.
  2. Приведение выполняет метод ПривестиЗначение() у описания типов. Он возвращает значение нужного типа или пустое значение этого типа, если превращение невозможно.
  3. Цикл по колонкам внутри цикла по строкам работает медленнее прямого присваивания. Для таблиц в сотни тысяч строк вынесите имена колонок в массив заранее.

После цикла замените ссылку: СтараяТаблица = НоваяТаблица;. Если таблицу вернула функция, верните из неё новую.

Добавление колонки и перенос значений в существующую таблицу

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

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

Имя колонки занято, пока старая колонка существует, поэтому приходится делать два прохода:

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

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

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

Минус способа в том, что колонка окажется в конце списка, а не на прежнем месте. Если порядок важен для вывода в табличный документ, выбирайте предыдущий вариант или выводите колонки по именам явно.

Метод Колонки.Удалить() безвозвратно сносит данные колонки. Не удаляйте старую колонку, пока не проверили, что временная заполнена корректно. На этапе отладки сначала выведите несколько строк в сообщения.

Универсальные типы: когда пересоздавать вообще не надо

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

Таблица.Колонки.Добавить("Значение");

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

Сравните подходы:

ПодходКогда подходитРиски
Новая таблицаСтруктура известна заранее, важен порядок колонокНужно переписать ссылку на таблицу
Новая колонка в существующей таблицеТаблицу нельзя заменить объектомКолонка уходит в конец, два прохода по данным
Колонка без типаДанные приходят разнороднымиНет контроля типов, неудобно на форме
Составной типДопустимо несколько известных типовНужно проверять тип перед использованием

Если нужно именно расширить допустимые типы, а не заменить, не перечисляйте всё заново. Описание типов можно собрать от исходного:

ТипШире = Новый ОписаниеТипов(Колонка.ТипЗначения, "Строка");

Здесь исходное описание дополняется типом Строка. Такой приём удобен при создании новой колонки на основе старой.

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

Тип колонки в 1С задаётся не просто именем, а описанием вместе с квалификаторами. Ошибки при смене типа чаще всего происходят именно из-за квалификаторов.

Для числа квалификатор задаёт разрядность и точность: Новый КвалификаторыЧисла(15, 2) означает до 15 цифр, две из них после запятой. Если в старой колонке были дробные значения, а в новой точность 0, дробная часть при записи отбросится. Для строки задаётся длина через КвалификаторыСтроки, и при слишком короткой длине значение обрежется. Для даты задаётся состав: дата, время или оба.

Как ведёт себя приведение:

  • 🔢 Строка в число: если строка содержит число в нормальной записи, оно будет получено; если нет, результат равен нулю.
  • 🔤 Число в строку: проще и надёжнее использовать Формат(Число, "ЧГ=0") или СтрШаблон, чем полагаться на неявное преобразование, которое подставляет разделители групп.
  • 📅 Строка в дату: корректно работает для записи вида 01.10.2026; нераспознанная строка превращается в пустую дату.
  • 🔗 Строка в ссылку: автоматически не получится, нужен поиск элемента по наименованию или коду отдельным запросом.

Поэтому после приведения стоит посчитать, сколько значений превратились в пустые:

НеПриведено = 0;
Для Каждого Строка Из НоваяТаблица Цикл
    Если Не ЗначениеЗаполнено(Строка.Сумма) Тогда
        НеПриведено = НеПриведено + 1;
    КонецЕсли;
КонецЦикла;
Сообщить("Не удалось привести: " + Формат(НеПриведено, "ЧГ=0"));

Учтите: ЗначениеЗаполнено считает нулевое число незаполненным. Если ноль в данных допустим, сравнивайте с исходной строкой: приведение дало ноль, а исходное значение не равно нулю.

Для колонки с датой выберите состав даты заранее: Новый КвалификаторыДаты(ЧастиДаты.Дата). Иначе время останется в значениях, и сравнение по равенству даст неожиданные результаты.

Таблица значений на форме: отдельная история

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

Порядок такой:

  1. Сохраните данные формы в обычную таблицу значений: ДанныеФормыВЗначение().
  2. Приведите колонки одним из способов выше.
  3. Удалите прежние реквизиты колонок, добавьте новые через ИзменитьРеквизиты().
  4. Верните данные в реквизит формы: ЗначениеВДанныеФормы().
  5. Пересоздайте элементы формы, привязанные к колонкам, иначе они останутся пустыми.

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

Проверка результата и отладка

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

В отладчике поставьте точку останова сразу после цикла переноса и откройте окно вычисления выражения. Три выражения закрывают почти всё:

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

Для итога по старой таблице сначала приведите значения, иначе сложить строки не получится. Проще всего посчитать контрольную сумму в том же цикле переноса и сравнить её с Итог() после цикла.

Если таблица большая, работает правило: меньше обращений к колонкам по имени внутри цикла. Обращение Строка[ИмяКолонки] по строковому имени медленнее обращения по свойству Строка.Сумма. Когда колонок немного и их имена известны, пишите их явно и не гоняйте универсальный цикл по всем колонкам.

Ещё один приём: если нужно просто получить таблицу с другими типами из результата запроса, не меняйте типы после выполнения. Приведите поле прямо в запросе: функция ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 2)) задаёт тип колонки на выходе. Это быстрее и не требует переноса данных вообще.

Что ломается чаще всего

Ошибки при смене типа колонки повторяются от проекта к проекту.

  • ❌ Попытка присвоить Колонка.ТипЗначения = Новый ОписаниеТипов(...). Платформа выдаст ошибку установки свойства только для чтения.
  • ❌ Удаление старой колонки до переноса данных. Значения пропали, а восстановить их можно только повторным выполнением запроса.
  • ❌ Изменение таблицы во время обхода. Не добавляйте и не удаляйте строки внутри Для Каждого по той же таблице; колонки менять в цикле по строкам тоже нельзя.
  • ❌ Неявное приведение строк с пробелами и неразрывными пробелами, пришедших из Excel. Перед приведением очистите строку: СокрЛП() и замена неразрывного пробела.
  • ❌ Потеря порядка колонок после добавления через Колонки.Добавить().

Если тип колонки не совпадает с ожиданием при отладке, остановите выполнение на точке после приведения и проверьте три вещи: тип значения в ячейке через ТипЗнч(), описание типа колонки и квалификаторы. Расхождение почти всегда в одном из них.

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

Можно ли изменить тип колонки, не создавая новую таблицу?
Напрямую нет, свойство ТипЗначения только читается. Используйте временную колонку: добавьте её с новым типом, перенесите значения, удалите старую и повторите для исходного имени.
Что произойдёт, если строка не превращается в число?
Метод ПривестиЗначение() вернёт ноль. Ошибки не будет, поэтому пересчитайте количество нулей и сверьте с исходными строками.
Как оставить колонке два типа, например число и строку?
Создайте описание типов с двумя типами: Новый ОписаниеТипов("Число, Строка"). Перед использованием значения проверяйте его тип через ТипЗнч().
Сохранится ли порядок колонок после добавления новой колонки в существующую таблицу?
Нет, новая колонка встанет в конец. Если порядок важен, соберите новую таблицу и добавляйте колонки в нужной последовательности.
Колонка таблицы на форме не меняется после преобразования. Почему?
Реквизиты колонок формы нужно пересоздавать через ИзменитьРеквизиты(), а данные передавать через ДанныеФормыВЗначение() и ЗначениеВДанныеФормы().