Очистка таблицы значений в 1С: строки, колонки и отборы

· 9 мин

Содержание

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

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

Полное удаление строк методом Очистить

Самый частый сценарий — выбросить все данные и начать заполнять таблицу заново. Для этого есть ровно один правильный инструмент:

ТЗ.Очистить();

После вызова ТЗ.Количество() вернёт 0, а все колонки останутся на месте. Это важно: если таблица передана в другую процедуру по ссылке или привязана к элементу формы, объект остаётся тем же — меняется только его содержимое.

Не пересоздавайте таблицу через ТЗ = Новый ТаблицаЗначений, если нужно просто очистить данные. Присваивание создаёт новый объект: старые колонки, индексы и привязки формы теряются, а прежние ссылки на таблицу продолжают указывать на старую, незатронутую копию.

Когда пересоздание всё же оправдано — если вместе со строками нужно сбросить и колонки, и вы собираете структуру с нуля. Тогда новый объект чище, чем последовательность Колонки.Очистить() плюс добавление колонок.

Метода Сбросить() у таблицы значений нет. Иногда его упоминают по аналогии с другими объектами, но в платформе за полную очистку отвечает именно Очистить(). Если встретили в чужом коде ТЗ.Сбросить() — это ошибка, такой код не скомпилируется.

Удаление отдельных строк по условию

Когда нужно убрать не всё, а только строки по отбору, работают два метода: НайтиСтроки() находит подходящие строки, Удалить() убирает их.

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

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

А вот так делать нельзя:

// ОШИБКА: изменение коллекции во время обхода
Для Каждого Строка Из ТЗ Цикл
    Если Строка.Статус = "Отменён" Тогда
        ТЗ.Удалить(Строка);
    КонецЦикла;
КонецЦикла;

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

Для Индекс = ТЗ.Количество() - 1 По 0 Цикл
    Если ТЗ[Индекс].Сумма = 0 Тогда
        ТЗ.Удалить(Индекс);
    КонецЦикла;
КонецЦикла;

Обратный цикл безопасен: удаление элемента сдвигает только те строки, что идут после него, а их вы уже прошли. Удалить() принимает и индекс (число), и саму строку типа СтрокаТаблицыЗначений — оба варианта рабочие.

НайтиСтроки() ищет только по точному совпадению. Диапазоны, «больше-меньше» и частичное вхождение структурой отбора не задать — для таких условий остаётся перебор строк вручную, как в обратном цикле выше.

Очистка и пересборка колонок

Колонки живут в отдельной коллекции ТЗ.Колонки. У неё свой набор методов.

Убрать все колонки сразу:

ТЗ.Колонки.Очистить();

Удалить одну конкретную — по имени, индексу или объекту колонки:

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

Добавить колонку обратно — с типом и заголовком:

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

Отдельная задача — очистить не колонку целиком, а значения в ней, оставив саму колонку. Удалять и пересоздавать колонку ради этого не нужно, есть ЗаполнитьЗначения():

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

Метод проставит переданное значение (Неопределено, 0, пустую строку — что укажете) во всех строках по перечисленным через запятую колонкам. Строки и структура таблицы при этом не меняются — обнуляются только данные в указанных колонках.

Частый порядок действий при смене структуры такой:

  1. Сохранить нужные данные, если они понадобятся.
  2. ТЗ.Колонки.Очистить() — убрать старую структуру.
  3. Добавить новые колонки через Колонки.Добавить().
  4. Заполнить таблицу заново.

Если же колонки менять не нужно, а требуется просто чистый лист с прежней структурой — вернитесь к Очистить() из первого раздела, он решает задачу одной строкой.

Бывает и обратная задача — убрать лишние колонки, но сохранить данные в остальных. Тут удобен Скопировать() со списком нужных колонок:

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

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

А чтобы вытащить значения одной колонки в отдельный массив перед её очисткой или удалением, есть ВыгрузитьКолонку():

МассивСумм = ТЗ.ВыгрузитьКолонку("Сумма");

Массив пригодится, если данные колонки нужны после того, как сама колонка исчезнет из таблицы.

Очистка больших таблиц без потери скорости

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

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

Удаление части строк. Вот где кроется ловушка. Поштучное Удалить() в цикле на больших объёмах даёт квадратичную сложность: каждое удаление сдвигает хвост таблицы, и суммарно операций получается порядка N². Когда удалить нужно значительную долю строк, дешевле собрать новую таблицу только из тех строк, что остаются:

ОтборСохраняемых = Новый Структура("Активный", Истина);
НовыйТЗ = ТЗ.Скопировать(ОтборСохраняемых);

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

Ускорение поиска. Если по таблице многократно вызывается НайтиСтроки(), добавьте индекс по колонкам отбора:

ТЗ.Индексы.Добавить("Статус");

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

Свёртка вместо чистки. Иногда задача формулируется как «убрать дубли и просуммировать». Вместо ручного удаления строк это делает Свернуть():

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

Первый параметр — колонки группировки, второй — колонки, значения которых складываются. Строки с одинаковыми значениями в колонках группировки схлопываются в одну.

ЗадачаМетодКогда применять
Убрать все строкиОчистить()Структура колонок нужна прежней
Убрать строки по точному условиюНайтиСтроки() + Удалить()Удаляемых строк немного
Оставить малую долю строкСкопировать(Отбор)Удалить нужно большинство строк
Убрать все колонкиКолонки.Очистить()Полностью меняете структуру
Обнулить одну колонкуЗаполнитьЗначения()Строки и структура остаются
Схлопнуть дублиСвернуть()Нужна группировка с суммированием
Что именно нужно очистить в таблице значений?

Пример: убрать лишние строки и свернуть остаток

Разберём частую связку — выбросить отменённые строки, а оставшиеся схлопнуть по номенклатуре с суммированием. Два метода подряд:

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

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

Проследим по числам. Допустим, на входе 5 строк: 2 со статусом Отменён и 3 активные, причём две из них — по одной и той же номенклатуре. После первого шага останется 3 строки. После свёртки две строки с одинаковой номенклатурой сложатся в одну — на выходе 2 строки с просуммированными количеством и суммой.

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

Очистка таблицы значений на управляемой форме

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

&НаСервере
Процедура ОчиститьТаблицуНаСервере()
    ДанныеТаблицы.Очистить();
КонецПроцедуры

Элемент таблицы на форме связан с реквизитом, поэтому после очистки реквизита список на экране обновится сам — отдельно перерисовывать его не нужно.

Целиком передавать таблицу значений между клиентом и сервером через параметр процедуры нельзя — этот тип не передаётся на клиент. Поэтому и очистку, и загрузку строк таблицы-реквизита выполняют в процедурах с директивой &НаСервере, а с клиента их только вызывают.

Если же таблица значений — локальная переменная внутри серверного модуля и на форме не показывается, никаких особенностей нет: работает обычный Очистить() из первого раздела.

Частые ошибки при очистке таблицы значений

Эти промахи встречаются чаще всего — проверьте себя по списку.

  • 🔁 Удаление внутри Для Каждого по самой таблице. Счётчик обхода сбивается, часть строк остаётся. Либо сначала НайтиСтроки() в массив, либо обратный цикл по индексам.
  • ➡️ Прямой цикл с удалением. Идти от нулевого индекса к последнему и удалять по пути — та же проблема сдвига. Только от последнего индекса к нулю.
  • 🆕 ТЗ = Новый ТаблицаЗначений вместо Очистить(). Теряются колонки, индексы и привязка к форме. Прежние ссылки на таблицу указывают на старый объект, и очистка «не срабатывает» для вызывающего кода.
  • 🧩 Путаница строк и колонок. Очистить() убирает строки, но не колонки. Если после очистки структура не нужна — это отдельное действие через Колонки.
  • 🔍 Ожидание диапазона от НайтиСтроки(). Метод ищет только точное равенство. Для условий «больше», «содержит», «между» — перебор строк вручную.
  • 👻 Выдуманный метод Сбросить(). Такого метода у таблицы значений нет, код с ним не скомпилируется.
  • 📋 Очистка копии вместо реквизита формы. На форме меняется только исходный реквизит — промежуточная переменная к элементу не привязана.

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

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