Копирование колонки таблицы значений в 1С: способы и код
Содержание
Скопировать колонку таблицы значений в 1С можно четырьмя способами. ВыгрузитьКолонку() быстро вынимает значения в массив. Скопировать() создаёт новую таблицу только с нужными колонками. Цикл по строкам даёт полный контроль над значениями. Запрос к таблице значений позволяет попутно отфильтровать и свернуть данные.
Выбор простой. Нужен только список значений: берите ВыгрузитьКолонку. Нужна новая таблица с частью колонок: Скопировать. Нужно преобразовать значения по дороге: цикл. Нужна группировка или соединение с другими данными: запрос.
Метода с названием СкопироватьКолонку у таблицы значений нет. Его часто ищут в справке и не находят. Есть СкопироватьКолонки() (во множественном числе), но он копирует только структуру, без данных. Разберём, что за чем стоит.
Какой способ выбрать
| Способ | Что получаете | Когда брать | Ограничение |
|---|---|---|---|
ВыгрузитьКолонку | Массив значений одной колонки | Нужен список без структуры таблицы | Только одна колонка за вызов |
Скопировать | Новая таблица с выбранными колонками и строками | Нужна «урезанная» копия таблицы | Колонки перечисляются именами |
| Цикл по строкам | Что угодно: колонка в другой таблице, массив, соответствие | Значения нужно менять при копировании | Самый медленный на больших объёмах |
| Запрос к ТЗ | Таблица после отбора, группировки, соединений | Копирование вместе с агрегацией | Сложнее код, нужны типы колонок |
Выгрузка колонки в массив и загрузка обратно
Начните с этого метода. Он решает задачу «взять все значения одной колонки» за один вызов.
Массив = ТЗ.ВыгрузитьКолонку("Номенклатура");
В массиве будет столько элементов, сколько строк в таблице, в том же порядке. Колонку можно указать по имени, по индексу или объектом ТЗ.Колонки.Номенклатура.
Обратная операция называется ЗагрузитьКолонку. Она кладёт значения массива в колонку, строку за строкой:
ТЗ2.ЗагрузитьКолонку(Массив, "Номенклатура");
Так выглядит перенос колонки из одной таблицы в другую. Но есть условие: в приёмнике сначала должны появиться строки и сама колонка. Метод не создаёт ни то, ни другое.
ТЗ2 = Новый ТаблицаЗначений;
ТЗ2.Колонки.Добавить("Номенклатура");
Для Каждого Элемент Из Массив Цикл
ТЗ2.Добавить();
КонецЦикла;
ТЗ2.ЗагрузитьКолонку(Массив, "Номенклатура");
Если нужны уникальные значения, не перебирайте массив руками. Выгрузите колонку в массив и переложите его в Соответствие, где ключ — значение.
Другой приём для уникальных значений: скопировать колонку в новую таблицу и свернуть её.
Уникальные = ТЗ.Скопировать(, "Номенклатура");
Уникальные.Свернуть("Номенклатура");
Массив = Уникальные.ВыгрузитьКолонку("Номенклатура");
Исходная таблица при этом не меняется, а в массиве остаются только неповторяющиеся значения.
Скопировать таблицу целиком или только нужные колонки
Метод Скопировать возвращает новую таблицу значений. Первый параметр задаёт строки (можно пропустить или передать структуру отбора), второй — список колонок через запятую.
// Только две колонки, все строки
НоваяТЗ = ТЗ.Скопировать(, "Номенклатура, Количество");
// Только строки по отбору
Отбор = Новый Структура("Склад", Склад);
НоваяТЗ = ТЗ.Скопировать(Отбор, "Номенклатура, Количество");
Изменения в новой таблице не затрагивают исходную. Это независимая копия, строки в ней — новые объекты.
Если нужна пустая заготовка с теми же колонками и типами, вызывайте СкопироватьКолонки():
Заготовка = ТЗ.СкопироватьКолонки();
Данных в ней не будет. Строки добавляйте сами. Это удобно, когда нужно отфильтровать таблицу вручную и сохранить структуру, включая типы.
Одна колонка в новую таблицу
Нужна таблица из одной колонки? Передайте её имя вторым параметром:
ТолькоНоменклатура = ТЗ.Скопировать(, "Номенклатура");
Колонки в результате идут в порядке перечисления, а не в порядке исходной таблицы.
Копирование колонки циклом по строкам
Цикл нужен, когда значения надо менять по пути: округлить, привести к другому типу, собрать из двух колонок. Для чистого копирования он избыточен, но как учебный пример показателен.
Допустим, в таблице ТЗ есть колонка Цена, а в ТЗ2 нужна колонка ЦенаСНДС, где значение умножено на 1,2.
ТЗ2 = ТЗ.Скопировать();
ТЗ2.Колонки.Добавить("ЦенаСНДС", Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(15, 2)));
Для Каждого Строка Из ТЗ2 Цикл
Строка.ЦенаСНДС = Окр(Строка.Цена * 1.2, 2);
КонецЦикла;
Проверим арифметику: при цене 100 получим 120,00, при цене 99,99 — 119,99 (99,99 × 1,2 = 119,988, округляем до 119,99).
Если исходная и целевая таблицы разные и строки соответствуют друг другу по порядку, идите по индексу:
Для Индекс = 0 По ТЗ.Количество() - 1 Цикл
ТЗ2[Индекс].Результат = ТЗ[Индекс].Источник;
КонецЦикла;
Индексы строк таблицы значений начинаются с нуля. Ошибка на единицу при границе цикла — одна из самых частых.
Не добавляйте и не удаляйте строки таблицы внутри Для Каждого по ней же. Если нужно удалить строки, собирайте их в массив и удаляйте после цикла, либо идите обратным циклом по индексам.
Копирование через запрос к таблице значений
В запросе таблицу значений можно использовать как источник. Её передают параметром и обращаются к ней в блоке ИЗ:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| СУММА(Т.Количество) КАК Количество
|ИЗ
| &ТЗ КАК Т
|СГРУППИРОВАТЬ ПО
| Т.Номенклатура";
Запрос.УстановитьПараметр("ТЗ", ТЗ);
Результат = Запрос.Выполнить().Выгрузить();
Здесь в новую таблицу уходят две колонки, причём количество уже просуммировано. Таким способом удобно копировать колонку «с группировкой». Если нужно ещё и соединить с данными из базы, запрос выигрывает у цикла по всем параметрам.
Условие: у колонок исходной таблицы должны быть заданы типы. Если колонка создана без типа (ТЗ.Колонки.Добавить("Количество")), запрос может отказаться работать с ней или вернуть неожиданные результаты. Поэтому колонки, которые пойдут в запрос, всегда создавайте с описанием типов.
Для переноса в запрос уместно знать и такой вариант: поместить таблицу значений во временную таблицу через МенеджерВременныхТаблиц и обращаться к ней по имени. Это нужно, если одна и та же таблица используется в нескольких запросах пакета.
Копирование колонки с условием
Часто нужны не все значения, а только подходящие. Вариантов два.
Первый: отобрать строки методом НайтиСтроки, затем пройти по найденному массиву.
Отбор = Новый Структура("Склад", Склад);
Найденные = ТЗ.НайтиСтроки(Отбор);
Результат = Новый Массив;
Для Каждого Строка Из Найденные Цикл
Результат.Добавить(Строка.Номенклатура);
КонецЦикла;
Второй: сначала Скопировать(Отбор, "Номенклатура"), затем ВыгрузитьКолонку. Он короче и не требует цикла, поэтому на больших таблицах работает быстрее.
Отбор по структуре сравнивает значения на равенство. Условия «больше», «меньше» или «содержит» так не задать. Для них пишите цикл с проверкой либо переходите на запрос.
Типы данных и составные типы
Когда колонка создаётся без типа, в неё можно положить что угодно. Это удобно в черновике, но осложняет копирование. После Скопировать и СкопироватьКолонки типы колонок сохраняются. А при ручном создании колонки в приёмнике вы задаёте их сами.
Типы = Новый ОписаниеТипов("Число, Строка");
ТЗ2.Колонки.Добавить("Значение", Типы);
Это составной тип: колонка принимает и число, и строку. Если вы кладёте в неё значение другого типа, платформа приведёт его к допустимому. Для типа, который не подходит, получите значение по умолчанию: пустую строку, ноль или Неопределено. Исключения не будет, поэтому потерю данных легко не заметить.
Чтобы привести значение явно, пользуйтесь методом описания типов:
Строка.Значение = Типы.ПривестиЗначение(ИсходноеЗначение);
Что стоит проверить перед копированием колонки между таблицами:
- 🔹 типы совпадают или тип приёмника шире типа источника;
- 🔹 у строк и чисел задана длина и точность: строка без ограничения длины и строка длиной 10 поведут себя по-разному;
- 🔹 ссылочные типы приёмника включают все нужные справочники и документы;
- 🔹 состав даты: если в приёмнике колонка с типом «Дата» и составом «Дата», время отбросится.
Не уверены в типе источника? Посмотрите ТЗ.Колонки.Номенклатура.ТипЗначения. Это объект ОписаниеТипов, из него можно получить список типов и квалификаторы.
Скорость на больших таблицах
Для тысяч строк разница между способами заметна, для сотен тысяч — критична. Общий порядок такой: быстрее всех встроенные методы (ВыгрузитьКолонку, Скопировать, Свернуть), затем запрос, медленнее всех цикл с обращением к полям по именам.
Что ускоряет работу:
- Не пишите в цикле
ТЗ.Колонки.Найти(...)для каждой строки. Получите колонки один раз до цикла. - Не вызывайте
ТЗ.Количество()в условии, если таблица меняется. Для обычного прохода это безопасно, но лучше сохранить значение в переменную. - Не добавляйте строки по одной, если можно загрузить массив целиком через
ЗагрузитьКолонку. - Для поиска по значению используйте индексы таблицы (
ТЗ.Индексы.Добавить("Номенклатура")) или методНайтиСтрокивместо вложенных циклов. - Если данные приходят из запроса, не выгружайте их в таблицу ради копирования одной колонки. Обработайте результат запроса напрямую.
Вложенный цикл «для каждой строки одной таблицы — искать в другой» на 50 000 × 50 000 строк даёт 2,5 миллиарда сравнений. Такой код висит минутами. Замените его на Соответствие по ключу или на запрос с соединением.
На сервере такие операции выполняйте в серверных процедурах: копирование таблицы значений на клиент и обратно тоже стоит времени. Передавайте таблицу между клиентом и сервером минимальное число раз.
Копирование между строками и в табличную часть
Иногда колонку нужно «скопировать» внутри одной таблицы: например, заполнить ЦенаСклада значениями из Цена. Здесь подойдёт цикл, но есть и короткий путь через массив:
ТЗ.ЗагрузитьКолонку(ТЗ.ВыгрузитьКолонку("Цена"), "ЦенаСклада");
Две колонки должны быть в таблице заранее. Значения переедут как есть, с приведением к типу приёмника.
Для табличной части документа в обработчиках используют два встроенных метода: Выгрузить() превращает табличную часть в таблицу значений, Загрузить(ТЗ) заменяет её содержимое. Колонки сопоставляются по именам. Типичный сценарий выглядит так:
- Выгрузить табличную часть в таблицу значений.
- Добавить или преобразовать нужную колонку (цикл,
ЗагрузитьКолонку). - Загрузить таблицу обратно.
Загрузка заменяет все строки табличной части. Если в ней были данные, которых нет в таблице значений, они пропадут. Для частичного обновления идите циклом по строкам табличной части и меняйте нужные поля.
Результат запроса можно получить и сразу в виде таблицы: Запрос.Выполнить().Выгрузить(). Колонки в ней повторяют поля запроса, а типы берутся из источников данных. Если в запросе поле составного типа, колонка тоже получится составной.
Ошибки при копировании колонок и как их лечить
Основные сообщения, которые встречаются при работе с колонками:
Поле объекта не обнаружено (Номенклатура): в таблице нет колонки с таким именем. Регистр букв значения не имеет, а вот опечатка или обращение к колонке другой таблицы — частая причина.Колонка с таким именем уже существует: вы вызываетеКолонки.Добавитьповторно. Перед добавлением проверьтеТЗ.Колонки.Найти("Имя") = Неопределено.Индекс за пределами допустимого диапазона: цикл по индексам вышел за размер таблицы. Граница верхняя —Количество() - 1.- Пустые значения после копирования. Колонка приёмника имеет другой тип, и платформа молча заменила значения значением по умолчанию.
Для отладки остановитесь точкой останова после копирования и откройте таблицу в отладчике. Сравните число строк, типы колонок и первые 2-3 значения. Обычно проблема видна сразу.
Для защиты от падения на нештатных данных оборачивайте опасные места в Попытка ... Исключение, но не прячьте ошибку молча. Запишите описание в журнал регистрации:
Попытка
Массив = ТЗ.ВыгрузитьКолонку("Номенклатура");
Исключение
ЗаписьЖурналаРегистрации("КопированиеКолонки",
УровеньЖурналаРегистрации.Ошибка,,,
ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
Прежде чем ловить исключение, проверьте условия простыми проверками: колонка есть, таблица не пуста, типы подходят. Так код читается проще, а исключения остаются для действительно непредвиденного.
Частые вопросы
Как скопировать несколько колонок таблицы значений?
ТЗ.Скопировать(, "Колонка1, Колонка2"). Получится новая таблица только с этими колонками и всеми строками.Чем `СкопироватьКолонки` отличается от `Скопировать`?
СкопироватьКолонки() создаёт пустую таблицу со структурой исходной. Скопировать() переносит ещё и строки с данными.Можно ли переименовать колонку при копировании?
Скопировать оставляет прежние имена. Переименовать можно через запрос (Т.Цена КАК ЦенаЗакупки) или создав в приёмнике колонку с новым именем и перенеся значения через ВыгрузитьКолонку/ЗагрузитьКолонку.Влияет ли копия на исходную таблицу?
Скопировать и ВыгрузитьКолонку возвращают независимые данные. Если же в ячейках лежат ссылки на объекты (например, структуры), они остаются общими.Как скопировать колонку в табличную часть документа?
Загрузить из таблицы значений и Выгрузить в неё. Колонки сопоставляются по именам, лишние пропускаются.