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

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

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

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

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

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

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

Как работает метод Скопировать() и когда его применять

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

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

ТаблицаИсточник.Колонки.Добавить("Номенклатура");

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

НоваяСтрока = ТаблицаИсточник.Добавить();

НоваяСтрока.Номенклатура = "Товар 1";

НоваяСтрока.Количество = 10;

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

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

// Копируем только строки, где Количество > 5, и только две колонки

Отбор = Новый Структура("Количество", 10);

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

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

Как перенести данные в существующую таблицу через Выгрузить() и Загрузить()

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

// ТаблицаПриемник уже существует, например реквизит формы

ТаблицаПриемник.Загрузить(ТаблицаИсточник.Выгрузить());

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

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

Как скопировать таблицу в табличную часть документа или справочника

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

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

Запрос.Текст = "ВЫБРАТЬ

| Товары.Номенклатура КАК Номенклатура,

| Товары.КоличествоОстаток КАК Количество

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Товары";

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

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

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

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

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

НоваяСтрока.Номенклатура = СтрокаИсточника.Товар;

НоваяСтрока.Количество = СтрокаИсточника.Количество * Коэффициент;

КонецЦикла;

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

Как скопировать часть строк по условию

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

Второй путь — метод НайтиСтроки(), который возвращает массив найденных строк. Его удобно использовать, когда найденные строки нужно не только скопировать, но и дополнительно обработать:

Отбор = Новый Структура("Склад", СкладОтгрузки);

НайденныеСтроки = ТаблицаИсточник.НайтиСтроки(Отбор);

Для Каждого Строка Из НайденныеСтроки Цикл

НоваяСтрока = ТаблицаПриемник.Добавить();

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

КонецЦикла;

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

Для сложных условий, которые не выразить структурой отбора (диапазоны, сравнения «больше/меньше», условия ИЛИ), эффективнее всего использовать запрос с помещением таблицы значений во временную таблицу — так отбор выполняется средствами СУБД.

Сравнение способов копирования

Скопировать()

Полная копия со структурой; подходит для создания независимой таблицы. Не подходит, если приёмник уже существует и связан с формой

Загрузить(Выгрузить())

Перенос данных в существующую таблицу или табличную часть. Требует совпадения имён колонок, очищает приёмник

Цикл с ЗаполнитьЗначенияСвойств()

Максимальный контроль над каждой строкой и возможность преобразований. Медленнее на больших объёмах

Запрос с временной таблицей

Сложные отборы и соединения больших таблиц. Требует написания текста запроса и менеджера временных таблиц

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

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

Первый — скопировать таблицу и сразу очистить результат:

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

ПустаяКопия.Очистить();

Второй — скопировать колонки отдельно через свойство Колонки и метод Скопировать() коллекции колонок, если нужно построить структуру вручную. Также структуру колонок можно получить через Выгрузить() с отбором пустого массива строк:

ПустаяКопия = ТаблицаИсточник.Скопировать(Новый Массив);

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

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

Производительность и расход памяти при копировании

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

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

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

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

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

Количество строк в приёмнике
Норма

Совпадает с количеством строк источника (или с ожидаемым числом при отборе)

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

Строк меньше — проверяйте отбор и имена колонок

Значения контрольной строки
Норма

Все поля заполнены значениями из источника

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

Часть полей пустая — имена колонок не совпадают

Независимость копий
Норма

Изменение копии не влияет на исходную таблицу

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

Меняются обе — выполнено присваивание вместо копирования

Структура колонок
Норма

Имена и типы колонок соответствуют ожиданиям

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

Лишние или отсутствующие колонки

Частые вопросы о копировании таблиц значений

Чем отличается присваивание Таблица2 = Таблица1 от метода Скопировать()?

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

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

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

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

Используйте построчный цикл с явным присваиванием полей: НоваяСтрока.РеквизитПриемника = СтрокаИсточника.КолонкаИсточника. Альтернатива — переименовать колонки источника методом Колонки.Найти().Имя или собрать нужные имена псевдонимами в запросе.

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

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

Как объединить две таблицы значений в одну?

Простейший способ — цикл по строкам второй таблицы с добавлением в первую через Добавить() и ЗаполнитьЗначенияСвойств(). Для больших таблиц эффективнее поместить обе во временные таблицы запроса и выполнить объединение через ОБЪЕДИНИТЬ ВСЕ.

Почему после Загрузить() в табличную часть часть полей пустая?

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

Итог

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

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