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

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

Как скопировать колонку из одной таблицы значений в другую в 1С

Как скопировать колонку из одной таблицы значений в другую в 1С: добавление колонки, перенос значений в цикле, объединение таблиц и типичные ошибки разработчика.

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

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

Ниже разобраны рабочие приёмы: простое копирование по индексу строки, перенос с сопоставлением по ключевому полю, копирование структуры колонки с сохранением типа, а также типичные ошибки, которые приводят к потере данных или к ошибкам исполнения.

Базовый способ: добавить колонку и перенести значения в цикле

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

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

Для Инд = 0 По ТаблицаИсточник.Количество() - 1 Цикл

ТаблицаПриемник[Инд].Сумма = ТаблицаИсточник[Инд].Сумма;

КонецЦикла;

Обращение ТаблицаПриемник[Инд] возвращает строку по индексу — это быстрее и надёжнее, чем вложенный цикл «Для Каждого», когда нужен синхронный обход двух таблиц. Если тип колонки не указать, будет создана колонка произвольного типа, и 1С определит тип по первому записанному значению, что иногда приводит к неожиданностям при дальнейшей обработке.

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

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

Если нужно перенести не только данные, но и точное описание колонки — тип, длину строки, точность числа, заголовок — возьмите описание из коллекции колонок источника. У каждой колонки есть свойства ТипЗначения, Заголовок, Ширина, которые можно передать в метод Добавить().

КолонкаИсточника = ТаблицаИсточник.Колонки.Найти("Контрагент");

Если КолонкаИсточника <> Неопределено Тогда

ТаблицаПриемник.Колонки.Добавить(

КолонкаИсточника.Имя,

КолонкаИсточника.ТипЗначения,

КолонкаИсточника.Заголовок);

КонецЕсли;

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

Перенос колонки с сопоставлением строк по ключу

На практике таблицы редко совпадают построчно: чаще колонку нужно «присоединить» к другой таблице по ключевому полю — например, по номенклатуре, контрагенту или номеру документа. В этом случае для каждой строки приёмника ищется соответствующая строка источника методом Найти().

ТаблицаПриемник.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));

Для Каждого СтрокаПриемника Из ТаблицаПриемник Цикл

СтрокаИсточника = ТаблицаИсточник.Найти(СтрокаПриемника.Номенклатура, "Номенклатура");

Если СтрокаИсточника <> Неопределено Тогда

СтрокаПриемника.Цена = СтрокаИсточника.Цена;

КонецЕсли;

КонецЦикла;

У этого подхода есть ограничение производительности: метод Найти() перебирает таблицу линейно, и на больших объёмах (десятки тысяч строк) цикл с поиском работает заметно медленно. Для ускорения перед циклом постройте индекс по ключевой колонке методом ТаблицаИсточник.Индексы.Добавить("Номенклатура") — поиск станет существенно быстрее.

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

Если ключевое поле может содержать NULL или пустые ссылки, добавьте проверку перед поиском. Поиск по Неопределено часто даёт ложные совпадения или, наоборот, не находит очевидные строки из-за различия пустой ссылки и Неопределено.
ПЗ
Практическое замечание

Альтернатива: соединение таблиц через запрос

Когда обе таблицы получены из базы или их нужно соединить по сложному условию, эффективнее не копировать колонку в цикле, а поместить обе таблицы во временные таблицы запроса и выполнить левое соединение. Запрос выполняется на сервере СУБД и работает быстрее встроенного языка на больших объёмах.

Запрос = Новый Запрос;

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

Запрос.Текст =

"ВЫБРАТЬ Т.Номенклатура, Т.Количество ПОМЕСТИТЬ Т1 ИЗ &Таб1 КАК Т;

|ВЫБРАТЬ Т.Номенклатура, Т.Цена ПОМЕСТИТЬ Т2 ИЗ &Таб2 КАК Т;

|ВЫБРАТЬ Т1.Номенклатура, Т1.Количество, Т2.Цена

|ИЗ Т1 КАК Т1 ЛЕВОЕ СОЕДИНЕНИЕ Т2 КАК Т2

|ПО Т1.Номенклатура = Т2.Номенклатура";

Запрос.УстановитьПараметр("Таб1", Таблица1);

Запрос.УстановитьПараметр("Таб2", Таблица2);

Результат = Запрос.Выполнить().Выгрузить();

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

Сравнение вариантов

Цикл по индексу

Подходит, когда таблицы одинаковой длины и порядок строк совпадает; самый быстрый и простой вариант

Цикл с Найти() по ключу

Подходит для сопоставления по ключевому полю; на больших таблицах требует индекса

Соединение запросом

Подходит для больших объёмов и сложных условий; требует помещения таблиц во временные таблицы

Скопировать() всей таблицы

Подходит, когда нужна вся таблица целиком, а не одна колонка; создаёт полную копию структуры и данных

Типичные ошибки и как их избежать

Самая частая ошибка — попытка обратиться к колонке, которой ещё нет в приёмнике: присваивание Строка.НоваяКолонка = Значение без предварительного Колонки.Добавить() вызывает ошибку «Поле объекта не обнаружено». Вторая типичная проблема — выход за границы массива строк, когда приёмник короче источника: обращение ТаблицаПриемник[Инд] с несуществующим индексом прерывает выполнение.

Третья группа ошибок связана с типами. Если колонка добавлена с типом «Число», а в источнике встречается строка или NULL, при присваивании значение либо будет приведено к значению по умолчанию (ноль), либо вызовет ошибку преобразования — в зависимости от контекста. Для разнородных данных добавляйте колонку с составным типом или без указания типа и контролируйте значения явно.

Типичные ошибки
01
Присваивание значения колонке до её добавления — ошибка «Поле объекта не обнаружено»
02
Обход по индексу без проверки длины приёмника — выход за границы таблицы
03
Добавление колонки с существующим именем — исключение, прерывающее код
04
Копирование без указания типа и последующая сортировка или итоги по колонке с неожиданным типом
05
Игнорирование результата Найти() — запись Неопределено или пропуск данных без контроля

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

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

В отладчике таблицу значений удобно смотреть через «Вычислить выражение» с последующим просмотром коллекции. Для вывода в журнал регистрации или сообщения пройдите по первым строкам и выведите значения ключевого поля и новой колонки — этого достаточно, чтобы убедиться, что сопоставление сработало правильно.

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

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

Наличие колонки
Норма

Колонки.Найти(Имя) возвращает колонку

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

Возвращается Неопределено — колонка не добавлена

Заполненность
Норма

Количество непустых значений совпадает с источником

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

Часть строк пуста — сопоставление по ключу не сработало

Итог по колонке
Норма

Итог() приёмника равен итогу источника

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

Итоги расходятся — потеряны или задублированы значения

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

Можно ли скопировать колонку одним методом, без цикла?

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

Что делать, если в приёмнике уже есть колонка с таким именем?

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

Как скопировать колонку только для части строк по условию?

Получите нужные строки методом НайтиСтроки() с параметрами отбора и переносите значения только в них. Либо в цикле добавьте проверку условия перед присваиванием.

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

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

Как быстро скопировать колонку между таблицами по 100 тысяч строк?

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

Можно ли переименовать колонку вместо копирования?

Да, если данные нужно оставить в той же таблице под другим именем: измените свойство Имя у объекта колонки. Это мгновенная операция без переноса данных.

Итог

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

Колонка копируется в два шага: Колонки.Добавить() плюс цикл переноса значений. Для сопоставления по ключу используйте Найти() с индексом или соединение запросом. Всегда проверяйте наличие колонки, длину таблиц и итоги после переноса.