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