Удаление колонок таблицы значений: синтаксис, индексы и безопасные приёмы

· 9 мин

Содержание

Колонку из таблицы значений удаляет метод Удалить у коллекции Колонки: ТЗ.Колонки.Удалить("Сумма"). Аргументом передают имя колонки, её числовой индекс или сам объект колонки — все три варианта рабочие. Данные удалённой колонки исчезают из всех строк, сама таблица и остальные колонки остаются.

На встроенном языке 1С колонки таблицы значений — это отдельная коллекция КоллекцияКолонокТаблицыЗначений, доступная через свойство Колонки. У неё свои методы: Добавить, Удалить, Найти, Количество, Сдвинуть. Удаление структуры идёт только через эту коллекцию — напрямую строкой или присваиванием колонку не убрать.

Метод работает одинаково на клиенте и на сервере — таблица значений доступна в обоих контекстах. Особый случай один: таблица, связанная с управляемой формой. Её колонки меняют через реквизиты формы, а не напрямую, и об этом стоит помнить до вызова Удалить.

Синтаксис метода Удалить у коллекции колонок

Метод принимает ровно один аргумент — ссылку на удаляемую колонку. Ссылку задают тремя способами:

  • 📝 По имени — строка: ТЗ.Колонки.Удалить("Сумма").
  • 🔢 По индексу — число, нумерация с нуля: ТЗ.Колонки.Удалить(0) удалит первую колонку.
  • 📦 По объекту — результат Найти или перебора: ТЗ.Колонки.Удалить(Колонка).

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

Какой способ выбрать, зависит от того, что известно о колонке:

Способ указанияКогда применятьРиск
По имени "Сумма"Имя известно, порядок колонок не важенИсключение, если имени нет — проверяйте через Найти
По индексу 2Нужна колонка на конкретной позицииСдвиг нумерации, выход за границы
По объекту КолонкаКолонка уже получена из Найти или перебораПрактически нет — объект гарантированно существует

В прикладном коде по умолчанию берите имя или объект: они не ломаются при изменении порядка колонок. Индекс нужен реже — когда позиция действительно часть логики.

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

// было три колонки
ТЗ.Колонки.Удалить("Сумма");
// стало две: Номенклатура, Количество

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

Удаление колонки по имени — самый надёжный вариант

Имя колонки не сдвигается при изменении структуры, поэтому удаление по имени — предпочтительный способ в прикладном коде. Вы явно указываете, что убираете, и не зависите от текущего порядка колонок.

ТЗ.Колонки.Удалить("НДС");

Если колонки с таким именем нет, платформа вызовет исключение вида «Колонка не найдена». Поэтому имя берите из того же источника, что и при добавлении, либо проверяйте его заранее (см. раздел про Найти).

Передавая имя из переменной или настройки, всегда проверяйте колонку через Найти перед удалением — иначе одна опечатка обрушит обработку с ошибкой.

Удаление по имени удобно, когда структуру таблицы формирует не ваш код: например, таблица пришла из Запрос.Выполнить().Выгрузить() или из результата внешней обработки, и порядок колонок заранее неизвестен, а имена — известны.

Удаление по индексу и сдвиг нумерации

Индекс — это позиция колонки в коллекции, отсчёт идёт с нуля. У таблицы с колонками Номенклатура, Количество, Сумма индексы равны 0, 1, 2 соответственно.

ТЗ.Колонки.Удалить(1); // удалит "Количество"

Главный нюанс: после удаления все колонки правее сдвигаются влево, их индексы уменьшаются на единицу. Удалили колонку с индексом 1 — бывшая колонка 2 становится колонкой 1. Это и есть источник большинства ошибок при удалении нескольких колонок в цикле.

Наглядно, что происходит с нумерацией:

ДействиеИндексы доИндексы после
Удалить(0)0,1,2,30,1,2 (бывшие 1,2,3)
Удалить(2) из 0,1,2,30,1,2,30,1,2 (бывшая 3 стала 2)
Удалить(последний)0,1,2,30,1,2 (сдвига нет)

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

Индекс за пределами диапазона (например, Удалить(5) при трёх колонках) вызывает исключение «Индекс находится за границами». Перед обращением по индексу сверяйтесь с ТЗ.Колонки.Количество().

Проверка колонки через Найти перед удалением

Метод Найти возвращает объект колонки, если она есть, и Неопределено, если колонки с таким именем в таблице нет. Это штатный способ убедиться, что удаление не упадёт с ошибкой.

Колонка = ТЗ.Колонки.Найти("Скидка");
Если Колонка <> Неопределено Тогда
    ТЗ.Колонки.Удалить(Колонка);
КонецЕсли;

Такой шаблон безопасен для любых данных: имя пришло из запроса, из реквизита формы или задано пользователем — удаление сработает, только если колонка действительно существует. Нет колонки — код просто ничего не делает, без исключения.

Найти принимает только имя колонки (строку). По индексу искать не нужно — к колонке по индексу обращаются напрямую через ТЗ.Колонки[Индекс].

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

Имена = Новый Массив;
Для Каждого Колонка Из ТЗ.Колонки Цикл
    Имена.Добавить(Колонка.Имя);
КонецЦикл;
Сообщить(СтрСоединить(Имена, ", "));

Пара удобных приёмов на основе Найти:

  • ✅ Удалить, только если есть — шаблон выше, без обработки исключений.
  • ✅ Переименовать вместо удаления — иногда проще сменить Колонка.Имя, чем удалять и добавлять заново, если меняется только заголовок.

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

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

СписокУдаления = "НДС,Скидка,Комментарий";
Для Каждого ИмяКолонки Из СтрРазделить(СписокУдаления, ",", Ложь) Цикл
    Колонка = ТЗ.Колонки.Найти(СокрЛП(ИмяКолонки));
    Если Колонка <> Неопределено Тогда
        ТЗ.Колонки.Удалить(Колонка);
    КонецЕсли;
КонецЦикл;

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

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

// оставить только первые 2 колонки, остальные удалить
Пока ТЗ.Колонки.Количество() > 2 Цикл
    ТЗ.Колонки.Удалить(ТЗ.Колонки.Количество() - 1);
КонецЦикл;

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

// удалить все колонки, имя которых начинается с "Врем"
Удаляемые = Новый Массив;
Для Каждого Колонка Из ТЗ.Колонки Цикл
    Если СтрНачинаетсяС(Колонка.Имя, "Врем") Тогда
        Удаляемые.Добавить(Колонка.Имя);
    КонецЕсли;
КонецЦикл;

Для Каждого ИмяКолонки Из Удаляемые Цикл
    ТЗ.Колонки.Удалить(ИмяКолонки);
КонецЦикл;

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

Чтобы убрать вообще все колонки, удобен цикл «пока есть что удалять» — он не зависит от текущего количества:

Пока ТЗ.Колонки.Количество() > 0 Цикл
    ТЗ.Колонки.Удалить(0);
КонецЦикл;

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

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

На выходе — таблица с теми же строками, но только с двумя перечисленными колонками. Исходную при необходимости заменяют: ТЗ = НоваяТЗ.

Какие ошибки возникают и как их разобрать

Почти все проблемы при удалении колонок сводятся к трём ситуациям. Разбор — что увидите и что проверить:

Диагностика: выберите симптом

Отдельный случай — таблица значений, которая является реквизитом управляемой формы и связана с таблицей на форме. Удалить её колонку обычным ТЗ.Колонки.Удалить(...) на клиенте не выйдет: структуру реквизитов формы меняют методом ИзменитьРеквизиты, а колонку, выведенную в элемент формы, предварительно убирают из этого элемента. Для обычной таблицы значений внутри кода (не связанной с формой) таких ограничений нет.

Если по колонке построен индекс через ТЗ.Индексы, удалите сначала индекс, а затем колонку — иначе платформа не даст убрать колонку, на которой держится индекс.

Что происходит с данными и скоростью

Удаление колонки — операция над структурой всей таблицы, а не над отдельной строкой. Платформа проходит по всем строкам и убирает значения удаляемой колонки, поэтому стоимость растёт с числом строк, а не колонок.

Практические ориентиры:

  • 🟢 На таблицах до нескольких тысяч строк удаление одной-двух колонок незаметно — доли миллисекунды.
  • 🟡 На десятках и сотнях тысяч строк удаление каждой колонки — это полный проход по таблице. Удаляете пять колонок по одной — получаете пять проходов.
  • 🔵 Когда колонок убрать нужно много, а оставить мало, Скопировать с нужными колонками обычно выгоднее: один проход вместо серии удалений.

Память освобождается сразу: значения удалённой колонки больше не хранятся. Если же таблица дальше не нужна целиком, не перебирайте колонки — присвойте переменной новую пустую таблицу или Неопределено, это дешевле.

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

Тот же подход для дерева значений

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

Дерево.Колонки.Удалить("ВспомогательнаяКолонка");

Разница лишь в том, что значение колонки хранится в каждой строке дерева на всех уровнях вложенности — платформа убирает его сразу по всей иерархии. Правила те же: проверка через Найти, осторожность с индексами, удаление по имени как основной способ. Поэтому код для таблицы значений переносится на дерево почти без изменений.

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

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

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