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