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

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

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

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

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

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

Как устроена задача и что проверить перед переносом

Таблица значений состоит из коллекции колонок (ТаблицаЗначений.Колонки) и коллекции строк. При копировании строк данные переносятся по именам колонок, поэтому первый шаг — сопоставить структуру источника и приёмника. Если в приёмнике нет колонки, которая есть в источнике, данные этой колонки просто не попадут в результат при использовании ЗаполнитьЗначенияСвойств без явного списка свойств.

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

Состав колонокИмена колонок источника и приёмника

Совпадают ли имена; есть ли лишние колонки в приёмнике

Типы колонокОписание типов каждой колонки

Не приведёт ли запись числа в строковую колонку к потере данных

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

Нужно ли очищать приёмник перед загрузкой или дополнять его

Проверить состав колонок можно прямо в отладчике или кодом:

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

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

Сообщить("В приёмнике нет колонки: " + Колонка.Имя);

КонецЕсли;

КонецЦикла;

Базовый способ: цикл с Добавить и ЗаполнитьЗначенияСвойств

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

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

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

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

КонецЦикла;

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

ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника, "Номенклатура, Количество, Цена");

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

Перенос отобранных строк через НайтиСтроки

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

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

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

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

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

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

КонецЦикла;

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

Быстрый перенос идентичных таблиц

Загрузка колонок

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

Для Сч = 1 По ТаблицаИсточник.Количество() Цикл

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

КонецЦикла;

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

ТаблицаПриемник.ЗагрузитьКолонку(

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

КонецЦикла;

Этот приём работает заметно быстрее построчного копирования на больших таблицах, но требует, чтобы приёмник до этого был пустым, иначе новые значения «затрут» данные существующих строк по индексу.

Объединение через запрос

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

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

Запрос.УстановитьПараметр("Таб1", ТаблицаПриемник);

Запрос.УстановитьПараметр("Таб2", ТаблицаИсточник);

Запрос.Текст =

"ВЫБРАТЬ Т.Номенклатура, Т.Количество

|ПОМЕСТИТЬ ВТ ИЗ &Таб1 КАК Т

|ОБЪЕДИНИТЬ ВСЕ

|ВЫБРАТЬ Т.Номенклатура, Т.Количество

|ИЗ &Таб2 КАК Т

|;

|ВЫБРАТЬ * ИЗ ВТ";

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

Ключевое слово ОБЪЕДИНИТЬ ВСЕ сохраняет дубликаты строк, а просто ОБЪЕДИНИТЬ убирает полностью совпадающие строки — выбирайте в зависимости от задачи. Заодно запрос позволяет сразу свернуть данные с суммированием количества.

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

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

Универсально, работает при разных структурах; медленнее на больших объёмах

ЗагрузитьКолонку

Быстро, но только для идентичных таблиц и пустого приёмника

Запрос с ОБЪЕДИНИТЬ ВСЕ

Лучшая производительность и возможность свёртки; требует совпадения типов колонок

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

Создаёт полную копию таблицы, а не дополняет существующую — подходит для замены, а не слияния

Типичные ошибки и подводные камни

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

Вторая ошибка — несовпадение типов колонок. Если в источнике колонка «Количество» имеет тип «Число(15,3)», а в приёмнике — «Число(10,0)», дробная часть будет округлена при записи. Проверяйте описания типов через Колонка.ТипЗначения, особенно когда приёмник создаётся вручную методом Колонки.Добавить.

Третья проблема — неочищенный приёмник. Если процедура переноса вызывается повторно (например, при перепроведении документа или повторной загрузке файла), строки задваиваются. Перед загрузкой либо вызывайте ТаблицаПриемник.Очистить(), либо убедитесь, что повторное добавление предусмотрено логикой.

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

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

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

СуммаИсточника = ТаблицаИсточник.Итог("Сумма");

СуммаПриемника = ТаблицаПриемник.Итог("Сумма");

Если СуммаПриемника - СуммаДоДобавления <> СуммаИсточника Тогда

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

КонецЕсли;

При отладке удобно просмотреть таблицу значений в табличном документе: в конфигураторе доступен просмотр содержимого через «Вычислить выражение» либо временный вывод через ТаблицаПриемник.ВыбратьСтроку() в толстом клиенте. В управляемом приложении таблицу можно вывести в табличный документ обходом строк.

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

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

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

Старое количество + число добавленных строк

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

Меньше ожидаемого или кратно больше (задвоение)

Итоги числовых колонок
Норма

Итог вырос ровно на сумму источника

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

Расхождение — потеря или дублирование данных

Значения в новых строках
Норма

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

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

Пустые колонки — несовпадение имён или типов

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

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

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

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

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

Как перенести строки, если имена колонок различаются?

ЗаполнитьЗначенияСвойств работает только по совпадающим именам. При разных именах присваивайте значения вручную: НоваяСтрока.Товар = СтрокаИсточника.Номенклатура. Альтернатива — переименовать колонки источника заранее или выполнить перенос запросом с псевдонимами полей.

Исчезнут ли строки источника после переноса?

Нет. Добавление строк в приёмник не изменяет источник — данные копируются по значениям примитивных типов. Учтите только, что значения ссылочных типов (ссылки на справочники, документы) копируются как ссылки на те же объекты, а не как новые объекты.

Что быстрее на больших таблицах — цикл или запрос?

На объёмах в десятки тысяч строк и выше запрос с ОБЪЕДИНИТЬ ВСЕ обычно заметно быстрее построчного цикла, поскольку обработка идёт на уровне движка платформы без пошагового исполнения встроенного кода. Для небольших таблиц разница несущественна, и проще использовать цикл.

Как избежать дублей при объединении таблиц?

Используйте в запросе ОБЪЕДИНИТЬ без ВСЕ — полностью совпадающие строки будут исключены. Если дубль определяется по ключевым полям (например, по номенклатуре), сгруппируйте результат запроса с агрегированием числовых колонок или перед добавлением проверяйте наличие строки через НайтиСтроки по ключу.

Итог

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

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