Удаление колонок из Таблицы значений: методы и примеры кода
Содержание
Чтобы убрать одну колонку из таблицы значений, вызовите Таблица.Колонки.Удалить(...) — в скобки передают имя колонки, её индекс или сам объект колонки. Отдельных методов УдалитьКолонку или ОчиститьКолонки в платформе нет: вся работа со структурой идёт через коллекцию Колонки.
Одну колонку убирают по имени, набор лишних — циклом, а всю структуру целиком — перебором, пока колонок не останется. Если же в таблице нужно оставить всего пару колонок, быстрее не удалять лишние по очереди, а скопировать нужные методом Скопировать.
Ниже — рабочие примеры на встроенном языке 1С 8.3 для каждого из этих случаев, разбор того, что происходит с данными и типами, и типичная ловушка с удалением внутри цикла.
Что входит в структуру таблицы значений
Таблица значений (ТаблицаЗначений) — это таблица в оперативной памяти. Её структуру задают колонки, а данные лежат в строках.
Колонки хранятся в коллекции Таблица.Колонки. Каждая колонка — объект со свойствами:
- 📌
Имя— идентификатор, по которому обращаются к значению в строке; - 📌
Заголовок— подпись для вывода на форму; - 📌
ТипЗначения— описание допустимых типов (ОписаниеТипов); - 📌
Ширина— ширина при показе.
У самой коллекции Колонки есть методы Добавить, Вставить, Удалить, Найти, Количество, Индекс и Сдвинуть. Именно Удалить нужен для нашей задачи.
Соберём таблицу, с которой будем работать дальше:
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
Доступ к значению в строке — через имя (Строка.Сумма) или индекс (Строка[2]). Поэтому удаление колонки сразу влияет на весь код, который к ней обращается.
Чаще всего таблицу получают не вручную, а из готового источника: Результат.Выгрузить() после выполнения запроса, Документ.Товары.Выгрузить() из табличной части или Отбор динамического списка. В таких таблицах лишние служебные колонки (технические ссылки, вспомогательные суммы) обычно и убирают — перед выводом в табличный документ, выгрузкой в Excel или передачей в другую процедуру. Для всех этих источников работает один и тот же Колонки.Удалить.
Удаление одной колонки по имени и по индексу
Метод Удалить принимает три вида аргумента — выбирайте удобный.
По имени — самый читаемый вариант:
Таблица.Колонки.Удалить("Сумма");
По индексу (нумерация с нуля — первая колонка имеет индекс 0):
Таблица.Колонки.Удалить(0); // удалит первую колонку — Номенклатура
По объекту колонки — когда вы уже получили колонку через Найти:
Колонка = Таблица.Колонки.Найти("Сумма");
Если Колонка <> Неопределено Тогда
Таблица.Колонки.Удалить(Колонка);
КонецЕсли;
Все три формы делают одно и то же: метод Удалить ничего не возвращает, он меняет коллекцию на месте. Имя удобно, когда оно известно заранее и код должен читаться; индекс — при переборе по номерам; объект колонки — когда вы уже получили её через Найти или Колонки[Индекс] и не хотите искать повторно.
Значения удалённой колонки во всех строках пропадают автоматически — отдельно их чистить не нужно.
Колонку удаляют по имени (Имя), а не по видимой подписи (Заголовок). Если на форме стоит заголовок «Цена закупки», а в коде колонка названа ЦенаЗакуп, в Удалить передают именно ЦенаЗакуп.
После удаления колонки по индексу индексы всех колонок, стоявших правее, уменьшаются на единицу. Если вы ориентируетесь на номера, пересчитайте их или перейдите на обращение по имени.
Если передать имя или индекс несуществующей колонки, платформа вызовет исключение. Как от этого защититься — в разделе про обработку ошибок ниже.
Как убрать сразу все колонки
Распространённая ошибка — искать метод Очистить у коллекции колонок. У таблицы значений есть метод Очистить(), но он удаляет строки, а структуру (колонки) оставляет нетронутой.
Чтобы снять именно колонки, перебирайте их, пока коллекция не опустеет:
Пока Таблица.Колонки.Количество() > 0 Цикл
Таблица.Колонки.Удалить(0);
КонецЦикл;
Каждый проход удаляет колонку с индексом 0, остальные сдвигаются на её место — так дойдём до конца без путаницы с индексами.
Снимать все колонки целиком приходится редко: без колонок таблица теряет смысл, ведь обращаться в строках становится не к чему. Обычно задача на деле другая — очистить данные
или заменить набор колонок. В первом случае нужен Очистить() (убирает строки), во втором — удалить старые колонки и добавить новые через Колонки.Добавить.
Если таблица вам больше не нужна в прежнем виде, проще не снимать колонки по одной, а пересоздать объект: Таблица = Новый ТаблицаЗначений;. Это быстрее и нагляднее, чем цикл.
Удаление списка лишних колонок в цикле
Когда нужно убрать несколько конкретных колонок, удобно задать их имена списком и пройти по нему. Проверка через Найти страхует от исключения, если какой-то колонки уже нет:
ЛишниеКолонки = СтрРазделить("Скидка,Комментарий,Ответственный", ",");
Для Каждого ИмяКолонки Из ЛишниеКолонки Цикл
Если Таблица.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
Таблица.Колонки.Удалить(ИмяКолонки);
КонецЕсли;
КонецЦикл;
Здесь удаление по имени безопасно: мы каждый раз заново ищем колонку, а не держим устаревший индекс.
А вот если удалять по условию с перебором по индексу, появляется ловушка. Представьте, что нужно снять все временные колонки, чьё имя начинается с Врем. Если идти по индексам от начала к концу, после каждого удаления соседние колонки сдвигаются — и часть вы пропустите.
Удаляйте такие колонки от конца к началу — тогда сдвиг индексов не затронет ещё не проверенные колонки.
Индекс = Таблица.Колонки.Количество() - 1;
Пока Индекс >= 0 Цикл
Колонка = Таблица.Колонки[Индекс];
Если СтрНачинаетсяС(Колонка.Имя, "Врем") Тогда
Таблица.Колонки.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикл;
Оператор Для ... По ... Цикл в 1С всегда считает вверх с шагом 1, поэтому обратный проход делают через Пока и ручной декремент счётчика.
Как удалить все колонки, кроме нужных
Зеркальная задача: оставить несколько колонок, а остальные — убрать, не перечисляя их поимённо. Задаём список нужных колонок и удаляем всё, чего в нём нет. Проход снова делаем от конца к началу:
СписокОставить = СтрРазделить("Номенклатура,Количество", ",");
Индекс = Таблица.Колонки.Количество() - 1;
Пока Индекс >= 0 Цикл
ИмяКолонки = Таблица.Колонки[Индекс].Имя;
Если СписокОставить.Найти(ИмяКолонки) = Неопределено Тогда
Таблица.Колонки.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикл;
СтрРазделить возвращает массив, а у массива метод Найти отдаёт Неопределено, если значения в нём нет — на этом и строится условие «колонки нет в списке нужных → удаляем». Сравнение идёт по имени колонки, поэтому список нужных задавайте именно именами, а не заголовками. Если имён много, вынесите их в константу или параметр процедуры, чтобы не дублировать строку в разных местах.
Когда оставить нужно заметно меньше колонок, чем удалить, перебор не обязателен — тот же результат даёт метод Скопировать с перечислением нужных колонок (см. раздел про альтернативу ниже).
Что происходит с данными и типами при удалении
Удаление колонки не зависит от её типа: ссылочная, число, составной тип или строка — колонка снимается одинаково, а её значения во всех строках теряются безвозвратно.
Важно помнить про связанный код:
- 🔸 После удаления колонки обращение
Строка.ИмяУдалённойКолонкивызовет ошибку «Поле объекта не обнаружено». Убирайте колонку только тогда, когда к ней больше нет обращений. - 🔸 Тип удаляемой колонки хранится в
Колонка.ТипЗначения— если данные ещё понадобятся, выгрузите их до удаления. - 🔸 Если по колонке были построены индексы через
Таблица.Индексы, после изменения структуры проверьте и при необходимости пересоберите их.
Количество строк при удалении колонки не меняется — таблица остаётся той же «высоты», просто в ней становится на один столбец меньше.
Типичный сбой выглядит так: процедура заполнения обращается к Строка.Сумма, а колонку Сумма удалили выше по коду. Платформа остановится с ошибкой «Поле объекта не обнаружено (Сумма)». Поэтому удаление структуры размещают после всех расчётов — либо убирают колонку в самом конце, перед выгрузкой результата. Если таблица передаётся в другую процедуру или на форму, убедитесь, что та не рассчитывает на удалённую колонку.
Проверка существования колонки и обработка ошибок
Главный источник ошибок — попытка удалить колонку, которой уже нет. Есть два подхода.
Проверка через Найти — предпочтительный способ. Метод возвращает объект колонки или Неопределено, исключение не возникает:
Если Таблица.Колонки.Найти("Сумма") <> Неопределено Тогда
Таблица.Колонки.Удалить("Сумма");
КонецЕсли;
Перехват через Попытка — когда проверку встроить неудобно:
Попытка
Таблица.Колонки.Удалить("МожетБытьНет");
Исключение
Сообщить("Не удалось удалить колонку: " + ОписаниеОшибки());
КонецПопытки;
Управлять логикой через Попытка/Исключение считается плохим стилем: исключения — для нештатных ситуаций. Для обычной проверки «есть колонка или нет» используйте Найти.
Удаление по индексу вне диапазона (например, Удалить(10) при трёх колонках) тоже приведёт к ошибке — сверяйтесь с Количество() перед обращением по номеру.
Если удаление колонок встречается в коде не раз, вынесите его в процедуру. Она принимает имена через запятую, пропускает лишние пробелы и молча игнорирует те колонки, которых уже нет:
Процедура УдалитьКолонкиБезопасно(Таблица, ИменаЧерезЗапятую)
Для Каждого Имя Из СтрРазделить(ИменаЧерезЗапятую, ",") Цикл
НайденнаяКолонка = Таблица.Колонки.Найти(СокрЛП(Имя));
Если НайденнаяКолонка <> Неопределено Тогда
Таблица.Колонки.Удалить(НайденнаяКолонка);
КонецЕсли;
КонецЦикл;
КонецПроцедуры
Вызов короткий и защищён от ошибок:
УдалитьКолонкиБезопасно(Таблица, "Скидка, Комментарий, Ответственный");
СокрЛП убирает пробелы вокруг имён, поэтому список можно писать с пробелами после запятых для читаемости.
Когда вместо удаления проще скопировать нужные колонки
Если из десяти колонок надо оставить две, удалять восемь по очереди — лишняя работа. Метод Скопировать создаёт новую таблицу только с указанными колонками:
НужнаяТаблица = Таблица.Скопировать(, "Номенклатура,Количество");
Первый параметр — отбор строк (пусто = все строки), второй — список имён колонок через запятую. На выходе — новый объект ТаблицаЗначений с нужной структурой, исходная таблица не меняется.
Этот приём удобнее удаления, когда:
| Ситуация | Что проще |
|---|---|
| Оставить мало колонок, убрать много | Скопировать с нужными |
| Убрать одну–две колонки | Колонки.Удалить |
| Нужна именно та же переменная | Удаление (копия создаёт новый объект) |
Скопировать создаёт полную копию данных в памяти. На больших таблицах это заметный расход — если объём критичен, удаляйте колонки в исходном объекте.
Если нужно, чтобы результат остался в прежней переменной, просто присвойте копию обратно: Таблица = Таблица.Скопировать(, "Номенклатура,Количество");.
Ещё один метод, который заодно убирает лишние колонки, — Свернуть. Он оставляет только колонки группировки и колонки суммирования, а строки при этом сворачивает по совпадающим значениям:
Таблица.Свернуть("Номенклатура", "Количество,Сумма");
После такого вызова в таблице останутся только Номенклатура, Количество и Сумма; строки с одинаковой номенклатурой сложатся в одну с просуммированными числами. Свернуть меняет исходную таблицу на месте и подходит, когда удаление колонок всё равно сопровождается группировкой данных — например, при подготовке итогов.
Частые вопросы
Существуют ли методы УдалитьКолонку или ОчиститьКолонки?
Таблица.Колонки.Удалить(...), а для удаления всех колонок используют цикл Пока.Удалится ли колонка вместе с данными?
Почему при удалении в цикле снимаются не все колонки?
Пока.Чем Очистить отличается от удаления колонок?
Таблица.Очистить() убирает все строки, но структуру (колонки) оставляет. Чтобы снять именно колонки, вызывайте Колонки.Удалить.Как изменить состав колонок у таблицы значений на управляемой форме?
ИзменитьРеквизиты() менеджера формы, а не удалением из Колонки «на лету». Для обычной таблицы значений в коде работает Колонки.Удалить.