Пустая копия ТЗ: колонки, типы, квалификаторы и данные
Содержание
Чтобы скопировать структуру таблицы значений в 1С без строк, вызовите НоваяТЗ = ТЗ.СкопироватьКолонки();. Метод создаёт новую таблицу с теми же колонками: имена, типы значений, заголовки и ширина переносятся, строки — нет.
Частая ошибка новичка — строка НоваяТЗ = ТЗ;. Она ничего не копирует. Обе переменные смотрят на один и тот же объект, и любое НоваяТЗ.Очистить() стирает исходные данные. Для копии всегда нужен метод, который создаёт новый объект: СкопироватьКолонки() или Скопировать().
Когда нужна копия колонок таблицы значений
Пустая таблица с той же структурой нужна чаще, чем кажется. Типичные случаи из практики:
- 📥 Накопитель результата. Вы обходите исходную таблицу, отбираете строки по сложному условию и складываете их в новую таблицу той же формы.
- 🧮 Сравнение «было — стало». Перед изменением данных снимаете копию, после — сравниваете две таблицы построчно.
- 🔀 Разделение на части. Одна выгрузка из запроса делится на несколько таблиц: по складам, по организациям, по периодам.
- 📤 Передача в другую процедуру. Вызываемый код должен получить «бланк» с правильными колонками и заполнить его сам.
- 🧪 Тесты и обработки. Нужна пустая таблица того же вида, что вернул запрос, чтобы проверить алгоритм на подготовленных строках.
Вручную описывать колонки в каждом таком месте — источник ошибок. Добавили поле в запрос, а в коде, который строит пустую таблицу, забыли. Копирование структуры с исходной таблицы снимает эту проблему: форма всегда совпадает с источником.
Метод СкопироватьКолонки: структура без строк
Это штатный способ, и в 9 случаях из 10 его достаточно.
// Полная копия структуры
НоваяТЗ = ТЗ.СкопироватьКолонки();
// Только нужные колонки — имена через запятую
НоваяТЗ = ТЗ.СкопироватьКолонки("Номенклатура, Количество, Сумма");
Что переносится в новую таблицу:
| Свойство колонки | Переносится |
|---|---|
| Имя | да |
| Тип значения (описание типов с квалификаторами) | да |
| Заголовок | да |
| Ширина | да |
| Строки с данными | нет |
| Индексы | нет, создавайте заново |
Параметр со списком колонок удобен, когда исходная таблица «толстая», а вам нужна лишь часть полей. Порядок колонок в новой таблице повторяет порядок в исходной.
💡 Если нужна структура почти целиком, кроме одной-двух колонок, проще скопировать всё и удалить лишнее:
НоваяТЗ = ТЗ.СкопироватьКолонки();
НоваяТЗ.Колонки.Удалить("СлужебноеПоле");
Индексы держите в голове отдельно. Если исходная таблица искалась через НайтиСтроки() по индексированной колонке, у копии индекса не будет, и поиск станет медленным. Добавьте его явно:
НоваяТЗ.Индексы.Добавить("Номенклатура");
Перенос структуры через цикл по коллекции Колонки
Цикл нужен, когда структуру надо не просто повторить, а изменить по дороге: переименовать колонки, сменить тип, добавить префикс, собрать таблицу из колонок двух разных источников.
Базовый вариант — точная копия, собранная руками:
НоваяТЗ = Новый ТаблицаЗначений;
Для Каждого Колонка Из ТЗ.Колонки Цикл
НоваяТЗ.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок, Колонка.Ширина);
КонецЦикла;
Метод Колонки.Добавить() принимает четыре параметра: имя, описание типов, заголовок и ширину. Все, кроме имени, необязательные. Если опустить тип, колонка примет значения любого типа.
Пример: объединить структуру двух таблиц
Задача: к колонкам выгрузки остатков добавить колонки из таблицы цен, не допустив дублей имён.
Итог = Остатки.СкопироватьКолонки();
Для Каждого Колонка Из Цены.Колонки Цикл
Если Итог.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
Итог.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок, Колонка.Ширина);
КонецЕсли;
КонецЦикла;
Проверка через Колонки.Найти() обязательна. Повторное добавление колонки с уже существующим именем вызывает ошибку времени выполнения.
Пример: список имён колонок строкой
Строку с именами удобно получить один раз и передать в СкопироватьКолонки(), Скопировать() или ЗаполнитьЗначенияСвойств():
Функция ИменаКолонок(ТЗ, Исключить = "")
Имена = Новый Массив;
Исключаемые = СтрРазделить(СтрЗаменить(Исключить, " ", ""), ",", Ложь);
Для Каждого Колонка Из ТЗ.Колонки Цикл
Если Исключаемые.Найти(Колонка.Имя) = Неопределено Тогда
Имена.Добавить(Колонка.Имя);
КонецЕсли;
КонецЦикла;
Возврат СтрСоединить(Имена, ",");
КонецФункции
Функции СтрРазделить() и СтрСоединить() доступны в платформе 8.3 начиная с релиза 8.3.6. На более старых релизах собирайте строку конкатенацией в цикле.
Пример: проверить, что структуры двух таблиц совпадают
Перед объединением двух таблиц через ЗаполнитьЗначенияСвойств() полезно убедиться, что у них одинаковый набор колонок и типов. Иначе часть данных потеряется без всякой ошибки.
Функция СтруктурыСовпадают(ТЗ1, ТЗ2)
Если ТЗ1.Колонки.Количество() <> ТЗ2.Колонки.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для Каждого Колонка Из ТЗ1.Колонки Цикл
Парная = ТЗ2.Колонки.Найти(Колонка.Имя);
Если Парная = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Если ЗначениеВСтрокуВнутр(Колонка.ТипЗначения) <> ЗначениеВСтрокуВнутр(Парная.ТипЗначения) Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Описания типов сравниваются через сериализацию: так в сравнение попадают и квалификаторы, а код выполняется на сервере. Функция не учитывает порядок колонок: для ЗаполнитьЗначенияСвойств() он не важен. Если вам нужен ещё и одинаковый порядок, сравнивайте колонки по индексу, а не по имени.
Копия таблицы значений вместе с данными
Если нужны и колонки, и строки, используйте Скопировать(). Метод возвращает новую независимую таблицу.
// Полная копия: все строки, все колонки
Копия = ТЗ.Скопировать();
// Строки по отбору, только часть колонок
Отбор = Новый Структура("Склад", Склад);
КопияСклада = ТЗ.Скопировать(Отбор, "Номенклатура, Количество");
// Конкретные строки — массивом
Строки = ТЗ.НайтиСтроки(Новый Структура("Отгружено", Ложь));
Неотгруженные = ТЗ.Скопировать(Строки);
Первый параметр принимает либо структуру отбора, либо массив строк исходной таблицы. Второй — список колонок через запятую. Отбор в структуре работает только на точное равенство. Условия «больше», «содержит», «не заполнено» реализуют циклом или запросом.
Перенос строк в уже готовую пустую таблицу
Бывает, что структура создана заранее, а строки добавляются по ходу. Здесь помогает ЗаполнитьЗначенияСвойств():
Результат = ТЗ.СкопироватьКолонки();
Для Каждого Строка Из ТЗ Цикл
Если Строка.Сумма > 10000 Тогда
НоваяСтрока = Результат.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЕсли;
КонецЦикла;
Метод копирует значения колонок с совпадающими именами. Колонки, которых нет в приёмнике, молча пропускаются. Это удобно, но и коварно: опечатку в имени колонки вы не заметите, просто получите пустое поле.
Глубокая копия через сериализацию
Скопировать() переносит значения как есть. Если в ячейке лежит изменяемый объект (другая таблица значений, массив, структура), в копию попадёт ссылка на тот же объект. Поменяете вложенную таблицу в копии — она поменяется и в оригинале.
Для полной независимости применяют сериализацию:
ГлубокаяКопия = ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(ТЗ));
⚠️ Этот приём работает только для сериализуемых значений и на больших таблицах заметно медленнее Скопировать(). Используйте его, только когда вложенные коллекции действительно меняются.
Типы данных и квалификаторы колонок
Тип колонки задаётся объектом ОписаниеТипов. Вместе с типом в нём хранятся квалификаторы: длина строки, разрядность и точность числа, состав даты.
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
ТЗ.Колонки.Добавить("Комментарий", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
ТЗ.Колонки.Добавить("ДатаОплаты", Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));
ТЗ.Колонки.Добавить("Контрагент", Новый ОписаниеТипов("СправочникСсылка.Контрагенты"));
Квалификаторы не формальность. Колонка с типом и квалификаторами приводит значение при записи:
| Тип колонки | Записали | Хранится |
|---|---|---|
| Число (15, 2) | 1234.567 | 1234.57 |
| Строка (5) | “Москва” | “Москв” |
| Дата (только дата) | 07.10.2026 14:35:00 | 07.10.2026 00:00:00 |
| Без типа | любое | как есть |
Поэтому при копировании структуры квалификаторы переносятся вместе с типом, и обрезание строк или округление чисел продолжится и в новой таблице. Если исходная колонка была строкой ограниченной длины, а в копию вы хотите писать длинные комментарии, тип придётся сменить.
Как сменить тип колонки при копировании
Свойство ТипЗначения у существующей колонки только для чтения. Новый тип задают при создании колонки. В цикле переноса структуры это делается просто:
НоваяТЗ = Новый ТаблицаЗначений;
Для Каждого Колонка Из ТЗ.Колонки Цикл
ТипКолонки = Колонка.ТипЗначения;
Если Колонка.Имя = "Комментарий" Тогда
ТипКолонки = Новый ОписаниеТипов("Строка"); // строка неограниченной длины
КонецЕсли;
НоваяТЗ.Колонки.Добавить(Колонка.Имя, ТипКолонки, Колонка.Заголовок, Колонка.Ширина);
КонецЦикла;
Если таблица уже заполнена, добавьте колонку с новым типом, перенесите значения, удалите старую и переименуйте новую:
Старая = ТЗ.Колонки.Найти("Комментарий");
Новая = ТЗ.Колонки.Вставить(ТЗ.Колонки.Индекс(Старая), "Комментарий_Нов", Новый ОписаниеТипов("Строка"), Старая.Заголовок);
ТЗ.ЗагрузитьКолонку(ТЗ.ВыгрузитьКолонку(Старая), Новая);
ТЗ.Колонки.Удалить(Старая);
Новая.Имя = "Комментарий";
Тип Null после выгрузки запроса
Таблица из Запрос.Выполнить().Выгрузить() часто содержит в типе колонки Null. Он появляется на полях из левого соединения. Копия структуры унаследует этот тип. Чтобы убрать его:
ТипБезNull = Новый ОписаниеТипов(Колонка.ТипЗначения, , "Null");
Конструктор принимает исходное описание, добавляемые и вычитаемые типы. Значения Null в данных при этом лучше заранее заменить в самом запросе через ЕСТЬNULL().
Скорость копирования больших таблиц
На таблицах в сотни тысяч строк разница между способами ощутима. Ориентиры из практики:
- ⚡
Скопировать()с отбором быстрее, чем цикл с проверкой условия иЗаполнитьЗначенияСвойств(). Платформа делает отбор внутри себя, без интерпретации встроенного языка на каждой строке. - 🗂️ Если отбор повторяется много раз по разным значениям, сначала создайте индекс:
ТЗ.Индексы.Добавить("Склад"). ТогдаСкопировать(Отбор)иНайтиСтроки()не перебирают всю таблицу. - 📦 Для переноса одной колонки целиком используйте пару
ВыгрузитьКолонку()/ЗагрузитьКолонку()вместо поэлементного цикла. - 🔢 Лишние колонки не копируйте. Укажите во втором параметре только нужные: меньше памяти, быстрее работа.
- 🧹 Если нужен итог по группам, а не сами строки,
ТЗ.Свернуть("Склад", "Количество, Сумма")на копии быстрее ручного суммирования.
Отдельная история — клиент и сервер. Объект ТаблицаЗначений в тонком и веб-клиенте недоступен. Все операции копирования делайте в серверных процедурах (&НаСервере или общий модуль с флагом «Сервер»). Гонять большие таблицы между клиентом и сервером ради копирования — самый дорогой путь.
Таблица на управляемой форме
Реквизит формы типа «Таблица значений» на клиенте — это ДанныеФормыКоллекция, а не таблица значений. Метода СкопироватьКолонки() у неё нет. Порядок такой:
&НаСервере
Процедура ПодготовитьКопиюНаСервере()
ТЗ = РеквизитФормыВЗначение("Товары");
ПустаяТЗ = ТЗ.СкопироватьКолонки();
// работа с ПустаяТЗ
КонецПроцедуры
Колонки реквизита формы задаются в конфигураторе. Программно поменять их состав можно только через ИзменитьРеквизиты(), и это отдельная задача.
Ошибки при копировании структуры и как их избежать
НоваяТЗ = ТЗ. Это одна и та же таблица. Замените на ТЗ.СкопироватьКолонки() или ТЗ.Скопировать().СкопироватьКолонки() или Скопировать() пропущено имя. Сверьте список или копируйте без параметра.Колонки.Найти() перед копированием.НоваяТЗ.Индексы.Добавить().Скопировать() переносит ссылки на вложенные коллекции. Нужна глубокая копия через ЗначениеВСтрокуВнутр().Ещё одна тонкость — порядок строк. Скопировать() сохраняет порядок исходной таблицы. Если код опирается на сортировку, вызывайте Сортировать() уже на копии, а не надейтесь на порядок источника после фильтрации.
Частые вопросы
Можно ли скопировать структуру дерева значений так же, как таблицы?
СкопироватьКолонки(). Создайте Новый ДеревоЗначений и перенесите колонки циклом через Колонки.Добавить() с теми же четырьмя параметрами.Копируются ли заголовки колонок?
СкопироватьКолонки(), и Скопировать() переносят заголовок и ширину вместе с именем и типом.Как получить пустую таблицу той же структуры, что у запроса, не выполняя его на всех данных?
ГДЕ 1 = 0, и выгрузите результат. Колонки и типы будут как у полного запроса.Чем отличается Скопировать() без параметров от СкопироватьКолонки()?
Скопировать() переносит строки с данными, СкопироватьКолонки() — только колонки. Если нужна пустая таблица, второй метод быстрее и не тратит память на данные.Можно ли поменять порядок колонок в копии?
Колонки.Вставить() с указанием индекса.