Удаление колонок из ТаблицыЗначений в 1С 8.3: Удалить, Скопировать, Свернуть
Содержание
Колонку из таблицы значений удаляет метод Колонки.Удалить(): Таблица.Колонки.Удалить("Комментарий"). Вместе с колонкой исчезают и данные в ней, обратно их не вернуть. Если нужно лишь не показывать колонку пользователю или получить таблицу с меньшим набором полей, есть способы мягче: Скопировать(), Свернуть() и скрытие элемента формы.
Код ниже рассчитан на платформу 1С 8.3 и встроенный язык. Он одинаково работает в обычных модулях, в модулях объектов и в серверных процедурах управляемых форм. Отдельно разберём форму: там таблица значений часто живёт как реквизит, и правила чуть другие.
Прежде чем удалять, решите, что вам на самом деле нужно. Три разные задачи решаются тремя разными приёмами, и перепутать их значит либо потерять данные, либо зря гонять большую таблицу по памяти.
Базовое удаление колонки методом Удалить
У коллекции Колонки метод Удалить принимает колонку одним из трёх способов: объектом колонки, именем или числовым индексом (с нуля).
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("Количество");
Таблица.Колонки.Добавить("Комментарий");
// По имени
Таблица.Колонки.Удалить("Комментарий");
// По объекту колонки
Колонка = Таблица.Колонки.Найти("Количество");
Если Колонка <> Неопределено Тогда
Таблица.Колонки.Удалить(Колонка);
КонецЕсли;
// По индексу: первая колонка
Таблица.Колонки.Удалить(0);
Удаление по индексу удобно в цикле, но хрупко: после каждого удаления индексы остальных колонок сдвигаются. Имя надёжнее, потому что не зависит от порядка.
Что происходит с существующими строками. Они остаются, а значение удалённой колонки в них пропадает. Обращение Строка.Комментарий после этого вызовет ошибку, потому что такого поля у строки больше нет.
| Способ указать колонку | Когда подходит | Риск |
|---|---|---|
| Имя строкой | Известен состав таблицы | Опечатка в имени вызывает исключение |
| Объект колонки | Колонка уже найдена через Найти() | Объект нельзя использовать после удаления |
| Индекс | Нужно удалить «все, начиная с N-й» | Индексы сдвигаются после каждого удаления |
Удаление нескольких колонок сразу
Метода «удалить список» у коллекции нет, поэтому колонки удаляют циклом. Имена берите из массива, а не из таблицы, которую вы же и меняете:
ЛишниеКолонки = СтрРазделить("Комментарий,Служебное,Флаг", ",");
Для Каждого ИмяКолонки Из ЛишниеКолонки Цикл
Если Таблица.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
Таблица.Колонки.Удалить(ИмяКолонки);
КонецЕсли;
КонецЦикла;
Проверка через Найти() защищает от исключения, если колонки в таблице уже нет. Это важно, когда таблица приходит из запроса или из чужой процедуры, и её состав вы не контролируете.
Если нужно оставить только несколько колонок, а удалить «всё остальное», обратный цикл по индексам короче и не требует списка исключений:
ОставитьКолонки = СтрРазделить("Номенклатура,Количество", ",");
Для Сч = 1 По Таблица.Колонки.Количество() Цикл
Колонка = Таблица.Колонки[Таблица.Колонки.Количество() - Сч];
Если ОставитьКолонки.Найти(Колонка.Имя) = Неопределено Тогда
Таблица.Колонки.Удалить(Колонка);
КонецЕсли;
КонецЦикла;
Здесь Таблица.Колонки.Количество() - Сч считается заново на каждом шаге, а верхняя граница цикла вычислена один раз. Идём с конца, поэтому удаление не сдвигает ещё не просмотренные колонки.
Таблица без лишних колонок: Скопировать и ВыгрузитьКолонки
Удалять колонки в исходной таблице не всегда нужно. Часто нужна её уменьшенная копия: для передачи в другую процедуру, для вывода или записи в регистр. Тогда исходник остаётся нетронутым.
Метод Скопировать() принимает отбор строк и список колонок через запятую:
НоваяТаблица = Таблица.Скопировать(, "Номенклатура, Количество");
Первый параметр пропущен, значит копируются все строки. Во втором перечислены только нужные колонки. Типы значений и порядок колонок в копии берутся из исходной таблицы.
Можно одновременно отфильтровать строки. Отбор задают структурой:
Отбор = Новый Структура("Склад", Склад);
НоваяТаблица = Таблица.Скопировать(Отбор, "Номенклатура, Количество");
Другой вариант, когда данные не нужны вовсе, а нужна «пустая оболочка»: ВыгрузитьКолонки() возвращает таблицу с теми же колонками, но без строк. Потом из неё можно удалить лишнее и заполнить своими данными.
Шаблон = Таблица.ВыгрузитьКолонки();
Шаблон.Колонки.Удалить("Комментарий");
Свернуть как способ убрать колонки
Метод Свернуть(ПоляГруппировки, ПоляСуммирования) оставляет в таблице только перечисленные колонки: все остальные удаляются. Строки с одинаковыми значениями полей группировки при этом объединяются, а числа в полях суммирования складываются.
Таблица.Свернуть("Номенклатура", "Количество");
После вызова в таблице две колонки, Номенклатура и Количество, причём каждая номенклатура встречается по одному разу. Если вам нужно именно удаление колонок без объединения строк, Свернуть не подойдёт: он схлопнет дубли. Для этого случая берите Скопировать.
Пример с числами. Было четыре строки: яблоки 5, груши 3, яблоки 2, груши 4. После свёртки по номенклатуре останется две строки: яблоки 7, груши 7. Если вы ожидали получить четыре строки, это не тот метод.
Скрыть колонку, не удаляя её
Иногда колонка нужна в коде, но пользователю её показывать незачем. Например, там лежит служебная ссылка или код для обработки. Удалять такую колонку нельзя, поэтому её прячут.
Варианты зависят от того, где отображается таблица:
- 📋 Табличный документ или макет. Колонки таблицы значений в нём не выводятся сами, вы формируете вывод кодом и просто не выводите лишнее.
- 🖥 Управляемая форма. Таблица на форме показывает колонки, которые вы разместили как элементы. Колонку-реквизит можно не выносить на форму вовсе или скрыть её свойством
Видимость. - 📊 Динамический список и СКД. Там колонки управляются настройками, а не методами таблицы значений.
Свойства самой колонки таблицы значений (Имя, Заголовок, Ширина, ТипЗначения) удалить колонку не позволяют. Заголовок и Ширина влияют только на отображение в обычной форме, а ширину в 0 ставить не стоит: колонка формально остаётся и путает при отладке.
Если колонка нужна только для промежуточных расчётов, заведите её в начале процедуры и удалите в конце. Так таблица не потащит служебные данные дальше по цепочке вызовов.
Производительность на больших таблицах
На тысячах строк стоимость операций заметна. Что стоит держать в голове:
- ⚙️
Колонки.Удалить()меняет структуру, и платформе приходится перестраивать каждую строку. Одна операция на таблицу из 100 000 строк быстрая, а вот десять подряд могут ощутимо подтормаживать. - ⚙️
Скопировать()с нужным набором колонок делает один проход и сразу даёт готовый результат. Он обычно выгоднее, чем «скопировать всё, потом удалять по одной». - ⚙️ Если таблица пришла из запроса, лучше сразу выбрать в запросе только нужные поля. Лишнюю колонку проще не получить, чем потом удалять.
- ⚙️ Не удаляйте колонки внутри цикла по строкам. Структуру нужно менять до обхода или после него.
Сравним подходы на практике.
| Задача | Рациональный способ | Что плохо |
|---|---|---|
| Оставить 3 колонки из 20 | Скопировать(, "А,Б,В") | 17 вызовов Удалить подряд |
| Убрать одну служебную колонку в конце | Колонки.Удалить("Имя") | Копировать всю таблицу ради одной колонки |
| Получить пустую таблицу той же структуры | ВыгрузитьКолонки() | Копировать и очищать строки |
| Объединить дубли и оставить итоги | Свернуть(...) | Ручной цикл с накоплением |
Для таблиц до нескольких тысяч строк разница незаметна, выбирайте тот способ, что понятнее читать. Оптимизация нужна, когда в таблице десятки и сотни тысяч строк, а операция выполняется на сервере при каждом обращении пользователя.
Ошибки при удалении колонок
Исключения возникают в трёх типовых ситуациях.
1. Колонки с таким именем нет. Вызов Колонки.Удалить("Коментарий") с опечаткой завершится ошибкой выполнения. Защита одна: сначала Найти(), затем Удалить. Для колонок, которые вы сами только что создали, проверка не нужна.
2. Обращение к удалённому полю. После удаления строка больше не знает про это поле. Выражение Строка.Комментарий даст сообщение вида Поле объекта не обнаружено (Комментарий). Ищите места, где значение читается позже по коду, в том числе в вызываемых процедурах и в условиях выбора.
3. Использование объекта колонки после удаления. Переменная Колонка ссылается на удалённый объект. Любая попытка прочитать у неё Имя или передать в другой метод приведёт к исключению. Присваивайте результат Найти() локальной переменной и не пользуйтесь ей после Удалить.
Для кода, который может получить таблицу неожиданной структуры, оборачивайте удаление в проверку, а не в Попытка. Проверка быстрее и не маскирует настоящие ошибки:
Процедура УдалитьКолонкуЕслиЕсть(Таблица, ИмяКолонки)
Если Таблица.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
Таблица.Колонки.Удалить(ИмяКолонки);
КонецЕсли;
КонецПроцедуры
Таблица.Колонки и сверьте регистр и написание. Затем используйте Найти() перед удалением.Управляемые формы: реквизит, элементы и клиент-сервер
В управляемой форме таблица значений обычно хранится как реквизит типа ТаблицаЗначений, а на форме показывается элемент «Таблица» с колонками-элементами. Здесь есть два отличия от обычного кода.
Данные и элементы разделены. Колонка реквизита и колонка элемента формы — разные вещи. Чтобы пользователь перестал видеть колонку, достаточно скрыть элемент:
Элементы.ТаблицаКомментарий.Видимость = Ложь;
Данные при этом остаются в реквизите, а код продолжает с ними работать. Это самый безопасный способ.
Структура реквизита меняется через ИзменитьРеквизиты. Если колонка реквизита формы создана динамически, её удаляют так же, как и добавляли, — списком удаляемых реквизитов. Для этого собирают массив путей вида Таблица.Колонка и передают вторым параметром метода ИзменитьРеквизиты. Перед этим нужно убрать с формы элемент, который эту колонку отображает. Метод работает на сервере и перерисовывает форму.
Если колонка описана в конфигураторе, то есть задана при проектировании формы, программно её не удалить: правится сама форма в конфигураторе.
Таблица значений на сервере. Когда данные приходят с клиента, их получают через ДанныеФормыВЗначение(Реквизит, Тип("ТаблицаЗначений")), правят как обычную таблицу и возвращают обратно ЗначениеВДанныеФормы. После такого возврата структура колонок реквизита не меняется. Колонку, которой нет в реквизите, туда не загрузишь, поэтому лишние поля удаляйте до возврата.
Серверный вызов с передачей большой таблицы с клиента дорог. Если колонки вам нужны только на сервере, не гоняйте их на клиент и обратно: выделите сервер в отдельную процедуру и работайте там.
Для тех, кто пишет внешние обработки, правило то же: в обработке и в расширении различий нет, структура таблицы значений меняется одинаково.
Что выбрать: короткая шпаргалка
Чтобы не держать в голове все способы, ориентируйтесь на задачу.
Таблица.Колонки.Удалить("Имя"), лучше с проверкой через Найти(). Данные колонки будут потеряны.Таблица.Скопировать(, "Колонка1, Колонка2").Таблица.Свернуть("Группа", "Сумма"): остальные колонки исчезнут, строки с одинаковой группой объединятся.Видимость = Ложь, данные в реквизите остаются.Частые вопросы
Можно ли удалить колонку из таблицы значений, пока по ней идёт цикл?
Для Каждого по строкам усложняет код и легко приводит к обращению к несуществующему полю.Удалится ли колонка из таблицы, которую вернул запрос?
Выгрузить() — обычная таблица значений, колонки в ней удаляются тем же методом. Но проще выбрать в запросе только нужные поля.Как узнать, есть ли колонка в таблице?
Таблица.Колонки.Найти("Имя"). Если колонки нет, результат — Неопределено.Можно ли переименовать колонку вместо удаления и создания новой?
Имя, его можно изменить, но делайте это осторожно: старые обращения по прежнему имени перестанут работать.