Удаление колонок из ТаблицыЗначений в 1С 8.3: Удалить, Скопировать, Свернуть

· 9 мин

Содержание

Колонку из таблицы значений удаляет метод Колонки.Удалить(): Таблица.Колонки.Удалить("Комментарий"). Вместе с колонкой исчезают и данные в ней, обратно их не вернуть. Если нужно лишь не показывать колонку пользователю или получить таблицу с меньшим набором полей, есть способы мягче: Скопировать(), Свернуть() и скрытие элемента формы.

Код ниже рассчитан на платформу 1С 8.3 и встроенный язык. Он одинаково работает в обычных модулях, в модулях объектов и в серверных процедурах управляемых форм. Отдельно разберём форму: там таблица значений часто живёт как реквизит, и правила чуть другие.

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

Базовое удаление колонки методом Удалить

У коллекции Колонки метод Удалить принимает колонку одним из трёх способов: объектом колонки, именем или числовым индексом (с нуля).

Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("Количество");
Таблица.Колонки.Добавить("Комментарий");

// По имени
Таблица.Колонки.Удалить("Комментарий");

// По объекту колонки
Колонка = Таблица.Колонки.Найти("Количество");
Если Колонка <> Неопределено Тогда
    Таблица.Колонки.Удалить(Колонка);
КонецЕсли;

// По индексу: первая колонка
Таблица.Колонки.Удалить(0);

Удаление по индексу удобно в цикле, но хрупко: после каждого удаления индексы остальных колонок сдвигаются. Имя надёжнее, потому что не зависит от порядка.

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

Способ указать колонкуКогда подходитРиск
Имя строкойИзвестен состав таблицыОпечатка в имени вызывает исключение
Объект колонкиКолонка уже найдена через Найти()Объект нельзя использовать после удаления
ИндексНужно удалить «все, начиная с N-й»Индексы сдвигаются после каждого удаления

Удаление нескольких колонок сразу

Метода «удалить список» у коллекции нет, поэтому колонки удаляют циклом. Имена берите из массива, а не из таблицы, которую вы же и меняете:

ЛишниеКолонки = СтрРазделить("Комментарий,Служебное,Флаг", ",");

Для Каждого ИмяКолонки Из ЛишниеКолонки Цикл
    Если Таблица.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
        Таблица.Колонки.Удалить(ИмяКолонки);
    КонецЕсли;
КонецЦикла;

Проверка через Найти() защищает от исключения, если колонки в таблице уже нет. Это важно, когда таблица приходит из запроса или из чужой процедуры, и её состав вы не контролируете.

Если нужно оставить только несколько колонок, а удалить «всё остальное», обратный цикл по индексам короче и не требует списка исключений:

ОставитьКолонки = СтрРазделить("Номенклатура,Количество", ",");

Для Сч = 1 По Таблица.Колонки.Количество() Цикл
    Колонка = Таблица.Колонки[Таблица.Колонки.Количество() - Сч];
    Если ОставитьКолонки.Найти(Колонка.Имя) = Неопределено Тогда
        Таблица.Колонки.Удалить(Колонка);
    КонецЕсли;
КонецЦикла;

Здесь Таблица.Колонки.Количество() - Сч считается заново на каждом шаге, а верхняя граница цикла вычислена один раз. Идём с конца, поэтому удаление не сдвигает ещё не просмотренные колонки.

Таблица без лишних колонок: Скопировать и ВыгрузитьКолонки

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

Метод Скопировать() принимает отбор строк и список колонок через запятую:

НоваяТаблица = Таблица.Скопировать(, "Номенклатура, Количество");

Первый параметр пропущен, значит копируются все строки. Во втором перечислены только нужные колонки. Типы значений и порядок колонок в копии берутся из исходной таблицы.

Можно одновременно отфильтровать строки. Отбор задают структурой:

Отбор = Новый Структура("Склад", Склад);
НоваяТаблица = Таблица.Скопировать(Отбор, "Номенклатура, Количество");

Другой вариант, когда данные не нужны вовсе, а нужна «пустая оболочка»: ВыгрузитьКолонки() возвращает таблицу с теми же колонками, но без строк. Потом из неё можно удалить лишнее и заполнить своими данными.

Шаблон = Таблица.ВыгрузитьКолонки();
Шаблон.Колонки.Удалить("Комментарий");

Свернуть как способ убрать колонки

Метод Свернуть(ПоляГруппировки, ПоляСуммирования) оставляет в таблице только перечисленные колонки: все остальные удаляются. Строки с одинаковыми значениями полей группировки при этом объединяются, а числа в полях суммирования складываются.

Таблица.Свернуть("Номенклатура", "Количество");

После вызова в таблице две колонки, Номенклатура и Количество, причём каждая номенклатура встречается по одному разу. Если вам нужно именно удаление колонок без объединения строк, Свернуть не подойдёт: он схлопнет дубли. Для этого случая берите Скопировать.

Пример с числами. Было четыре строки: яблоки 5, груши 3, яблоки 2, груши 4. После свёртки по номенклатуре останется две строки: яблоки 7, груши 7. Если вы ожидали получить четыре строки, это не тот метод.

Скрыть колонку, не удаляя её

Иногда колонка нужна в коде, но пользователю её показывать незачем. Например, там лежит служебная ссылка или код для обработки. Удалять такую колонку нельзя, поэтому её прячут.

Варианты зависят от того, где отображается таблица:

  • 📋 Табличный документ или макет. Колонки таблицы значений в нём не выводятся сами, вы формируете вывод кодом и просто не выводите лишнее.
  • 🖥 Управляемая форма. Таблица на форме показывает колонки, которые вы разместили как элементы. Колонку-реквизит можно не выносить на форму вовсе или скрыть её свойством Видимость.
  • 📊 Динамический список и СКД. Там колонки управляются настройками, а не методами таблицы значений.

Свойства самой колонки таблицы значений (Имя, Заголовок, Ширина, ТипЗначения) удалить колонку не позволяют. Заголовок и Ширина влияют только на отображение в обычной форме, а ширину в 0 ставить не стоит: колонка формально остаётся и путает при отладке.

Если колонка нужна только для промежуточных расчётов, заведите её в начале процедуры и удалите в конце. Так таблица не потащит служебные данные дальше по цепочке вызовов.

Производительность на больших таблицах

На тысячах строк стоимость операций заметна. Что стоит держать в голове:

  • ⚙️ Колонки.Удалить() меняет структуру, и платформе приходится перестраивать каждую строку. Одна операция на таблицу из 100 000 строк быстрая, а вот десять подряд могут ощутимо подтормаживать.
  • ⚙️ Скопировать() с нужным набором колонок делает один проход и сразу даёт готовый результат. Он обычно выгоднее, чем «скопировать всё, потом удалять по одной».
  • ⚙️ Если таблица пришла из запроса, лучше сразу выбрать в запросе только нужные поля. Лишнюю колонку проще не получить, чем потом удалять.
  • ⚙️ Не удаляйте колонки внутри цикла по строкам. Структуру нужно менять до обхода или после него.

Сравним подходы на практике.

ЗадачаРациональный способЧто плохо
Оставить 3 колонки из 20Скопировать(, "А,Б,В")17 вызовов Удалить подряд
Убрать одну служебную колонку в концеКолонки.Удалить("Имя")Копировать всю таблицу ради одной колонки
Получить пустую таблицу той же структурыВыгрузитьКолонки()Копировать и очищать строки
Объединить дубли и оставить итогиСвернуть(...)Ручной цикл с накоплением

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

Ошибки при удалении колонок

Исключения возникают в трёх типовых ситуациях.

1. Колонки с таким именем нет. Вызов Колонки.Удалить("Коментарий") с опечаткой завершится ошибкой выполнения. Защита одна: сначала Найти(), затем Удалить. Для колонок, которые вы сами только что создали, проверка не нужна.

2. Обращение к удалённому полю. После удаления строка больше не знает про это поле. Выражение Строка.Комментарий даст сообщение вида Поле объекта не обнаружено (Комментарий). Ищите места, где значение читается позже по коду, в том числе в вызываемых процедурах и в условиях выбора.

3. Использование объекта колонки после удаления. Переменная Колонка ссылается на удалённый объект. Любая попытка прочитать у неё Имя или передать в другой метод приведёт к исключению. Присваивайте результат Найти() локальной переменной и не пользуйтесь ей после Удалить.

Для кода, который может получить таблицу неожиданной структуры, оборачивайте удаление в проверку, а не в Попытка. Проверка быстрее и не маскирует настоящие ошибки:

Процедура УдалитьКолонкуЕслиЕсть(Таблица, ИмяКолонки)
    Если Таблица.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
        Таблица.Колонки.Удалить(ИмяКолонки);
    КонецЕсли;
КонецПроцедуры
Диагностика: выберите симптом

Управляемые формы: реквизит, элементы и клиент-сервер

В управляемой форме таблица значений обычно хранится как реквизит типа ТаблицаЗначений, а на форме показывается элемент «Таблица» с колонками-элементами. Здесь есть два отличия от обычного кода.

Данные и элементы разделены. Колонка реквизита и колонка элемента формы — разные вещи. Чтобы пользователь перестал видеть колонку, достаточно скрыть элемент:

Элементы.ТаблицаКомментарий.Видимость = Ложь;

Данные при этом остаются в реквизите, а код продолжает с ними работать. Это самый безопасный способ.

Структура реквизита меняется через ИзменитьРеквизиты. Если колонка реквизита формы создана динамически, её удаляют так же, как и добавляли, — списком удаляемых реквизитов. Для этого собирают массив путей вида Таблица.Колонка и передают вторым параметром метода ИзменитьРеквизиты. Перед этим нужно убрать с формы элемент, который эту колонку отображает. Метод работает на сервере и перерисовывает форму.

Если колонка описана в конфигураторе, то есть задана при проектировании формы, программно её не удалить: правится сама форма в конфигураторе.

Таблица значений на сервере. Когда данные приходят с клиента, их получают через ДанныеФормыВЗначение(Реквизит, Тип("ТаблицаЗначений")), правят как обычную таблицу и возвращают обратно ЗначениеВДанныеФормы. После такого возврата структура колонок реквизита не меняется. Колонку, которой нет в реквизите, туда не загрузишь, поэтому лишние поля удаляйте до возврата.

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

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

Что выбрать: короткая шпаргалка

Чтобы не держать в голове все способы, ориентируйтесь на задачу.

Что вам нужно сделать с колонкой?

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

Можно ли удалить колонку из таблицы значений, пока по ней идёт цикл?
Структуру таблицы лучше менять до или после обхода строк. Удаление колонки во время Для Каждого по строкам усложняет код и легко приводит к обращению к несуществующему полю.
Удалится ли колонка из таблицы, которую вернул запрос?
Результат Выгрузить() — обычная таблица значений, колонки в ней удаляются тем же методом. Но проще выбрать в запросе только нужные поля.
Как узнать, есть ли колонка в таблице?
Вызовите Таблица.Колонки.Найти("Имя"). Если колонки нет, результат — Неопределено.
Можно ли переименовать колонку вместо удаления и создания новой?
Да, у колонки есть свойство Имя, его можно изменить, но делайте это осторожно: старые обращения по прежнему имени перестанут работать.
Что быстрее: удалить колонки или скопировать нужные?
Для небольшого числа лишних колонок быстрее удаление, для большого — копирование нужного набора за один вызов.