Разработка и Конфигурация · 11 мин
Как скопировать таблицу значений в другую таблицу значений в 1С 8
Способы копирования таблиц значений в 1С 8: метод Скопировать(), выгрузка и загрузка колонок, копирование строк с отбором. Примеры кода и типичные ошибки.
Таблица значений в 1С 8 — один из самых используемых объектов для промежуточного хранения и обработки данных. Задача скопировать одну таблицу в другую возникает постоянно: при заполнении табличных частей документов, подготовке данных для отчётов, передаче данных между процедурами и временном сохранении состояния перед изменениями.
В зависимости от задачи нужно скопировать таблицу целиком вместе со структурой колонок, перенести только данные в уже существующую таблицу или выбрать часть строк по условию. Для каждого сценария встроенный язык предлагает свой инструмент, и выбор неправильного метода приводит либо к потере данных, либо к лишним затратам памяти.
Ниже разобраны рабочие способы копирования с примерами кода, указаны ограничения каждого подхода и типичные ошибки, которые допускают разработчики при работе с таблицами значений.
Как работает метод Скопировать() и когда его применять
Метод Скопировать() — самый простой способ получить полную копию таблицы значений. Он создаёт новый объект, в котором воспроизводятся и структура колонок (имена, типы, заголовки), и все строки с данными. Полученная таблица независима от исходной: изменения в одной не затрагивают другую.
ТаблицаИсточник = Новый ТаблицаЗначений;
ТаблицаИсточник.Колонки.Добавить("Номенклатура");
ТаблицаИсточник.Колонки.Добавить("Количество");
НоваяСтрока = ТаблицаИсточник.Добавить();
НоваяСтрока.Номенклатура = "Товар 1";
НоваяСтрока.Количество = 10;
ТаблицаПриемник = ТаблицаИсточник.Скопировать();
У метода есть два необязательных параметра: отбор строк и список копируемых колонок. Это позволяет за один вызов получить не всю таблицу, а только нужную часть:
// Копируем только строки, где Количество > 5, и только две колонки
Отбор = Новый Структура("Количество", 10);
ЧастичнаяКопия = ТаблицаИсточник.Скопировать(Отбор, "Номенклатура,Количество");
Важно понимать: Скопировать() всегда создаёт новый объект. Если приёмник уже существует и на него есть ссылки в других местах кода (например, таблица связана с элементом формы), присваивание нового объекта разорвёт эти связи. В таких случаях нужны другие подходы, описанные ниже.
Как перенести данные в существующую таблицу через Выгрузить() и Загрузить()
Когда таблица-приёмник уже создана и её нельзя заменить новым объектом, данные переносят парой методов Выгрузить() и Загрузить(). Метод Выгрузить() возвращает новую таблицу значений с данными источника, а Загрузить() заполняет приёмник строками из переданной таблицы.
// ТаблицаПриемник уже существует, например реквизит формы
ТаблицаПриемник.Загрузить(ТаблицаИсточник.Выгрузить());
У этого способа есть существенное ограничение: Загрузить() сопоставляет колонки по именам. Если в приёмнике нет колонки с таким именем, как в источнике, данные этой колонки будут потеряны без предупреждения. Обратная ситуация — лишние колонки в приёмнике — просто останутся незаполненными.
Ещё одна особенность: Загрузить() полностью заменяет содержимое приёмника, очищая его перед загрузкой. Если нужно добавить строки к существующим, используйте цикл с методом Добавить() или загрузку во временную таблицу с последующим переносом.
Как скопировать таблицу в табличную часть документа или справочника
Частая практическая задача — заполнить табличную часть документа данными из таблицы значений, полученной, например, из запроса или обработки. Табличная часть поддерживает метод Загрузить(), что делает перенос однострочным:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Товары";
ДокументОбъект.Товары.Загрузить(Запрос.Выполнить().Выгрузить());
Здесь критично совпадение имён колонок результата запроса с именами реквизитов табличной части. Поэтому в тексте запроса полям задают псевдонимы через КАК, точно повторяющие имена реквизитов. Типы данных тоже должны быть совместимы: строку нельзя загрузить в числовой реквизит.
Если имена не совпадают или нужно преобразовать значения, применяют построчный перенос в цикле. Он медленнее на больших объёмах, но даёт полный контроль над каждым полем:
Для Каждого СтрокаИсточника Из ТаблицаИсточник Цикл
НоваяСтрока = ДокументОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаИсточника.Товар;
НоваяСтрока.Количество = СтрокаИсточника.Количество * Коэффициент;
КонецЦикла;
- 1Проверьте имена колонок источника и реквизитов табличной части — они должны совпадать
- 2Убедитесь в совместимости типов данных соответствующих колонок
- 3При необходимости очистите табличную часть методом Очистить() или используйте Загрузить(), который делает это сам
- 4Выполните Загрузить() или построчный перенос в цикле
- 5Проверьте результат: количество строк и содержимое контрольных строк
Как скопировать часть строк по условию
Когда нужна не вся таблица, а строки, удовлетворяющие условию, есть два пути. Первый — параметр отбора метода Скопировать(), показанный выше. Он подходит для простых условий на равенство одного или нескольких полей.
Второй путь — метод НайтиСтроки(), который возвращает массив найденных строк. Его удобно использовать, когда найденные строки нужно не только скопировать, но и дополнительно обработать:
Отбор = Новый Структура("Склад", СкладОтгрузки);
НайденныеСтроки = ТаблицаИсточник.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
НоваяСтрока = ТаблицаПриемник.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЦикла;
Обратите внимание на ЗаполнитьЗначенияСвойств() — универсальный метод, который копирует значения совпадающих по именам свойств из одного объекта в другой. Он избавляет от ручного перечисления колонок и устойчив к добавлению новых колонок в таблицы. Ограничение то же, что у Загрузить(): переносятся только свойства с совпадающими именами.
Для сложных условий, которые не выразить структурой отбора (диапазоны, сравнения «больше/меньше», условия ИЛИ), эффективнее всего использовать запрос с помещением таблицы значений во временную таблицу — так отбор выполняется средствами СУБД.
Сравнение способов копирования
Полная копия со структурой; подходит для создания независимой таблицы. Не подходит, если приёмник уже существует и связан с формой
Перенос данных в существующую таблицу или табличную часть. Требует совпадения имён колонок, очищает приёмник
Максимальный контроль над каждой строкой и возможность преобразований. Медленнее на больших объёмах
Сложные отборы и соединения больших таблиц. Требует написания текста запроса и менеджера временных таблиц
Как скопировать только структуру колонок без данных
Иногда нужна пустая таблица с той же структурой, что у источника, — например, для накопления результатов обработки. Для этого у метода Скопировать() есть приём: передать отбор, которому заведомо не соответствует ни одна строка, или скопировать с пустым списком строк. На практике чаще используют два варианта.
Первый — скопировать таблицу и сразу очистить результат:
ПустаяКопия = ТаблицаИсточник.Скопировать();
ПустаяКопия.Очистить();
Второй — скопировать колонки отдельно через свойство Колонки и метод Скопировать() коллекции колонок, если нужно построить структуру вручную. Также структуру колонок можно получить через Выгрузить() с отбором пустого массива строк:
ПустаяКопия = ТаблицаИсточник.Скопировать(Новый Массив);
Передача пустого массива в качестве отбора строк — лаконичный способ получить таблицу с полной структурой и нулём строк, без промежуточного копирования всех данных.
Производительность и расход памяти при копировании
Каждое копирование таблицы значений — это выделение памяти под новый объект и построчное дублирование данных. На таблицах в десятки тысяч строк с широким набором колонок это становится ощутимым по времени и памяти, особенно на сервере при параллельной работе пользователей.
Поэтому перед копированием стоит задать себе вопрос: действительно ли нужна независимая копия? Если таблица только читается в вызываемой процедуре, достаточно передать её по ссылке через параметр — таблица значений передаётся по ссылке, и копирования не происходит. Копия нужна только тогда, когда вызываемый код будет изменять таблицу, а исходную трогать нельзя.
Для больших объёмов с отбором и преобразованием данных эффективнее запросы с временными таблицами: обработка идёт на уровне СУБД, а в память приложения попадает только итоговый результат. Это особенно актуально при соединении нескольких таблиц значений между собой.
Как проверить результат копирования
Совпадает с количеством строк источника (или с ожидаемым числом при отборе)
Строк меньше — проверяйте отбор и имена колонок
Все поля заполнены значениями из источника
Часть полей пустая — имена колонок не совпадают
Изменение копии не влияет на исходную таблицу
Меняются обе — выполнено присваивание вместо копирования
Имена и типы колонок соответствуют ожиданиям
Лишние или отсутствующие колонки
Частые вопросы о копировании таблиц значений
Чем отличается присваивание Таблица2 = Таблица1 от метода Скопировать()?
Присваивание не создаёт новый объект: обе переменные ссылаются на одну и ту же таблицу в памяти. Любое изменение через одну переменную видно через другую. Скопировать() создаёт независимый объект со своими данными.
Можно ли скопировать таблицу значений между клиентом и сервером?
Таблица значений не является сериализуемым объектом и напрямую не передаётся между клиентом и сервером в тонком клиенте. На форме её заменяет тип ДанныеФормыКоллекция, а для передачи данных используют структуры с массивами, хранилище значений или реквизиты формы соответствующего типа.
Как скопировать таблицу, если имена колонок в источнике и приёмнике разные?
Используйте построчный цикл с явным присваиванием полей: НоваяСтрока.РеквизитПриемника = СтрокаИсточника.КолонкаИсточника. Альтернатива — переименовать колонки источника методом Колонки.Найти().Имя или собрать нужные имена псевдонимами в запросе.
Сохраняются ли индексы при копировании таблицы?
Нет, индексы, созданные методом Индексы.Добавить(), в копию не переносятся. После копирования нужные индексы нужно создать заново, иначе поиск через Найти() и НайтиСтроки() будет работать медленнее на больших таблицах.
Как объединить две таблицы значений в одну?
Простейший способ — цикл по строкам второй таблицы с добавлением в первую через Добавить() и ЗаполнитьЗначенияСвойств(). Для больших таблиц эффективнее поместить обе во временные таблицы запроса и выполнить объединение через ОБЪЕДИНИТЬ ВСЕ.
Почему после Загрузить() в табличную часть часть полей пустая?
Загрузить() сопоставляет колонки только по именам. Проверьте, что имена колонок таблицы значений совпадают с именами реквизитов табличной части, включая регистр букв в запросе-псевдонимах, и что типы данных совместимы.
Что важно запомнить
Полная независимая копия создаётся методом Скопировать(), перенос данных в существующую таблицу — через Загрузить(Выгрузить()) или цикл с ЗаполнитьЗначенияСвойств(). Присваивание переменных не копирует таблицу, а создаёт вторую ссылку на тот же объект. Всегда проверяйте совпадение имён колонок и помните, что Загрузить() очищает приёмник перед заполнением.