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

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

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

Как скопировать структуру таблицы значений в 1С без данных: метод СкопироватьКолонки(), создание новой ТЗ, копирование только нужных колонок и типичные ошибки.

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

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

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

Метод СкопироватьКолонки() — основной способ

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

ТЗИсточник = ПолучитьТаблицуДанных(); // исходная таблица с данными

// Копируем только структуру — все колонки, без строк

ТЗПриемник = ТЗИсточник.СкопироватьКолонки();

Сообщить("Строк в приёмнике: " + ТЗПриемник.Количество()); // 0

Сообщить("Колонок: " + ТЗПриемник.Колонки.Количество()); // столько же, сколько в источнике

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

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

ТЗИтог = ТЗИсточник.СкопироватьКолонки("Номенклатура, Количество, Сумма");

Важно понимать: типы колонок копируются вместе со структурой. Если в исходной таблице колонка «Сумма» имела тип «Число» с длиной 15 и точностью 2, в новой таблице она будет иметь те же характеристики. Добавить строку с несовместимым типом значения не получится — значение будет приведено к типу колонки или обнулено.

Отличие Скопировать() от СкопироватьКолонки()

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

МетодЧто копируетКогда применять
СкопироватьКолонки()Только описания колонок, без строкНужна пустая таблица той же структуры для накопления данных
Скопировать()Структуру и все строкиНужна полная независимая копия таблицы с данными
Скопировать(Отбор)Структуру и строки, удовлетворяющие отборуНужна часть данных с сохранением структуры
Присваивание ТЗ2 = ТЗ1Ничего — копируется ссылка на тот же объектНе использовать для копирования: обе переменные указывают на одну таблицу

Отдельно стоит подчеркнуть последнюю строку таблицы. Простое присваивание ТЗ2 = ТЗ1 не создаёт копию — обе переменные начинают ссылаться на один и тот же объект в памяти. Любое изменение через одну переменную мгновенно видно через другую. Это одна из самых коварных ошибок при передаче таблиц между процедурами.

ТЗ2 = ТЗ1; // НЕ копия! Это ссылка на тот же объект

ТЗ2.Очистить(); // Очистится и ТЗ1 — данные потеряны

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

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

// Структура отбора: ключ — имя колонки, значение — искомое значение

Отбор = Новый Структура;

Отбор.Вставить("Склад", ВыбранныйСклад);

// Новая таблица: та же структура + только строки по отбору

ТЗПоСкладу = ТЗИсточник.Скопировать(Отбор);

Если же требуется сначала получить пустую структуру, а потом заполнить её в цикле с собственной логикой (например, с пересчётом значений), комбинируйте СкопироватьКолонки() и ручное добавление строк:

ТЗРезультат = ТЗИсточник.СкопироватьКолонки();

Для Каждого Строка Из ТЗИсточник Цикл

Если Строка.Количество > 0 Тогда

НоваяСтрока = ТЗРезультат.Добавить();

ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);

НоваяСтрока.Сумма = Строка.Количество * Строка.Цена; // свой расчёт

КонецЕсли;

КонецЦикла;

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

Создание структуры «с нуля» по описанию колонок

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

ТЗ = Новый ТаблицаЗначений;

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

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

ОписаниеСсылки = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");

ТЗ.Колонки.Добавить("Номенклатура", ОписаниеСсылки);

ТЗ.Колонки.Добавить("Наименование", ОписаниеСтроки);

ТЗ.Колонки.Добавить("Количество", ОписаниеЧисла);

ТЗ.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));

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

Ещё один вариант — получить структуру из результата запроса. Метод Запрос.Выполнить().Выгрузить() возвращает таблицу значений, колонки которой соответствуют полям запроса. Если данных не нужно, добавьте в запрос условие, которое заведомо не выполняется (например, ГДЕ ЛОЖЬ), — получите пустую таблицу с типизированными колонками.

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

Для дерева значений логика аналогична: метод Скопировать() копирует структуру вместе со строками и иерархией, а для получения только колонок универсального метода нет — используют копирование с последующей очисткой строк:

ДеревоКопия = ДеревоИсточник.Скопировать();

ДеревоКопия.Строки.Очистить(); // осталась только структура колонок

Структура табличной части объекта

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

ТЗСтруктура = ДокументОбъект.Товары.Выгрузить();

ТЗСтруктура.Очистить(); // пустая таблица со структурой табличной части

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

Типичные ошибки и проверка результата

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

Типичные ошибки
01
Присваивание ТЗ2 = ТЗ1 вместо копирования — обе переменные ссылаются на один объект, очистка одной очищает и другую
02
Использование Скопировать() там, где нужна только структура — лишний расход памяти и времени на дублирование строк
03
Опечатка в имени колонки в параметре СкопироватьКолонки("Имя") — платформа выдаст ошибку о ненайденной колонке
04
Ожидание, что скопируются индексы: индексы таблицы в новую таблицу не переносятся, их нужно добавлять заново через Колонки.Индексы
05
Попытка вставить значение несовместимого типа в типизированную колонку — значение будет приведено к типу или потеряно без предупреждения

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

Если ТЗПриемник.Колонки.Количество() <> ТЗИсточник.Колонки.Количество() Тогда

ВызватьИсключение "Структура скопирована не полностью";

КонецЕсли;

Для Каждого Колонка Из ТЗИсточник.Колонки Цикл

Если ТЗПриемник.Колонки.Найти(Колонка.Имя) = Неопределено Тогда

ВызватьИсключение "В копии отсутствует колонка " + Колонка.Имя;

КонецЕсли;

КонецЦикла;

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

ТЗПриемник.Колонки.Найти("Номенклатура"); // проверка наличия

ТЗПриемник.Индексы.Добавить("Номенклатура");

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

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

Число строк в новой таблице
Норма

0 строк при использовании СкопироватьКолонки()

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

Строки присутствуют — вероятно, вызван Скопировать() вместо СкопироватьКолонки()

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

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

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

Колонок меньше или типы отличаются — проверьте параметр метода

Независимость объектов
Норма

Очистка копии не влияет на исходную таблицу

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

Изменения видны в обоих объектах — использовано присваивание вместо копирования

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

Копируются ли типы колонок при использовании СкопироватьКолонки()?

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

Как скопировать структуру, если исходная таблица хранится в реквизите формы?

Реквизит формы типа «ТаблицаЗначений» поддерживает те же методы. Например: НоваяТЗ = РеквизитФормыВЗначение("ТаблицаНаФорме").СкопироватьКолонки(); — сначала реквизит преобразуется в объект, затем копируется структура. Для обратного отображения используйте ЗначениеВРеквизитФормы().

Можно ли скопировать структуру только части колонок и добавить свои?

Да. Сначала вызовите СкопироватьКолонки("Колонка1, Колонка2") с нужным списком, затем добавьте собственные колонки через Колонки.Добавить() с явным описанием типов. Порядок колонок можно скорректировать методом Сдвинуть() коллекции колонок.

Почему после копирования не работает быстрый поиск Найти()?

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

Чем отличается Очистить() от создания новой таблицы?

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

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

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

Итог

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

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