Разработка и Конфигурация · 10 мин
Как удалить массив строк из таблицы значений в 1С
Способы удаления массива строк из таблицы значений 1С: цикл с конца, фильтрация через индексы, НайтиСтроки и Удалить. Примеры кода, ошибки и проверка результата.
Задача удалить в 1С массив строк из таблицы значений возникает постоянно: при очистке временных данных после отбора, при исключении отклонённых документов из обработки, при синхронизации табличных частей. Встроенного метода «удалить массив» в языке нет, поэтому разработчику приходится выбирать между циклом, методом Удалить по объекту строки и пересозданием таблицы через запрос или отбор. Каждый подход имеет свои ограничения по скорости и безопасности.
Главная ловушка — удаление строк внутри прямого перебора. Когда вы удаляете строку, на которую сейчас ссылается итератор, индексы оставшихся строк сдвигаются, и часть данных либо пропускается, либо вызывает ошибку обращения к несуществующему элементу. Ниже разобраны рабочие варианты без этой проблемы.
Как устроена проблема удаления строк в таблице значений
Таблица значений — это коллекция с упорядоченными индексами. Когда вы удаляете строку с индексом 3, строка с индексом 4 становится строкой с индексом 3, и так далее до конца таблицы. Если цикл идёт вперёд и удаляет текущий элемент, следующая итерация фактически перепрыгивает через одну строку.
Метод Удалить() принимает либо индекс строки, либо сам объект строки таблицы значений. Оба варианта рабочие, но ведут себя по-разному: удаление по индексу требует контроля порядка обхода, а удаление по объекту строки безопасно, если ссылки на строки собраны заранее в отдельный массив.
Отдельно стоит помнить, что табличная часть объекта (документа или справочника) — это не таблица значений, хотя синтаксис похож. Для табличных частей принципы те же, но после изменений объект нужно записать, иначе удаление останется только в памяти.
Способ 1: удаление по индексу в обратном цикле
Самый надёжный вариант — идти по таблице с конца. При удалении последней строки индексы предыдущих не меняются, поэтому пропусков не возникает. Для этого используется цикл с вычисляемым диапазоном.
Для Индекс = 1 По ТаблицаДанных.Количество() Цикл
ТекущийИндекс = ТаблицаДанных.Количество() - Индекс;
СтрокаТаблицы = ТаблицаДанных[ТекущийИндекс];
Если СтрокаТаблицы.Пометить Тогда
ТаблицаДанных.Удалить(ТекущийИндекс);
КонецЕсли;
КонецЦикла;
Такой код удаляет все строки, у которых реквизит «Пометить» равен истине. Условие может быть любым: сравнение по номенклатуре, по сумме, по дате. Важно только, чтобы вычисление индекса шло от конца таблицы к началу.
Этот способ подходит, когда критерий удаления проверяется по значениям в самой строке и не требует предварительного отбора. Он работает одинаково и для таблицы значений, и для табличной части объекта.
Способ 2: сначала собрать строки в массив, потом удалить
Если у вас уже есть массив строк — например, полученный методом НайтиСтроки() по отбору — удаление выполняется простым перебором этого массива. Здесь удаление идёт по объекту строки, а не по индексу, поэтому сдвиг индексов не мешает.
Отбор = Новый Структура("Статус", "Отклонено");
СтрокиКУдалению = ТаблицаДанных.НайтиСтроки(Отбор);
Для Каждого СтрокаКУдалению Из СтрокиКУдалению Цикл
ТаблицаДанных.Удалить(СтрокаКУдалению);
КонецЦикла;
НайтиСтроки возвращает именно массив строк, что прямо отвечает на вопрос, как в 1С удалить массив строк из таблицы: перебираете массив и передаёте каждый элемент в Удалить(). Ссылки на объекты строк остаются валидными, даже когда таблица уже изменилась после первых удалений.
Отбор в структуре поддерживает только равенство. Если нужно условие «больше», «не равно» или проверка по нескольким полям с «ИЛИ», НайтиСтроки не подойдёт — используйте обратный цикл или запрос.
- 1Сформируйте структуру отбора с полями и значениями для поиска
- 2Вызовите Таблица.НайтиСтроки(Отбор) и получите массив строк
- 3Переберите массив циклом «Для Каждого» и вызовите Таблица.Удалить(Строка)
- 4Проверьте Таблица.Количество() до и после — разница должна совпасть с размером массива
Способ 3: пересоздание таблицы через запрос или отбор
Когда нужно удалить не несколько строк, а значительную часть большой таблицы, быстрее не удалять, а заново сформировать результат. Таблица значений выгружается в запрос, накладывается условие ГДЕ НЕ(условие удаления), и результат загружается обратно.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Т.Номенклатура, Т.Количество
|ПОМЕСТИТЬ ВТ ИЗ &Таблица КАК Т
|;
|ВЫБРАТЬ * ИЗ ВТ ГДЕ НЕ ВТ.Количество = 0";
Запрос.УстановитьПараметр("Таблица", ТаблицаДанных);
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
Для таблиц в десятки и сотни тысяч строк этот подход заметно быстрее поэлементного удаления, потому что движок запроса обрабатывает данные пакетно. Минус — теряются ссылки на старые объекты строк, если они где-то хранились, и требуется аккуратно описывать типы колонок при передаче таблицы параметром.
Альтернатива без запроса — метод Скопировать() с отбором: создаётся новая таблица только с нужными строками, а старая переменная переназначается. Это проще в коде, но тоже создаёт новый объект таблицы.
Сравнение способов удаления
Универсален, любые условия, работает с табличными частями. Требует аккуратного вычисления индекса.
Простой и читаемый код, но отбор только на равенство. Хорош для точечного удаления.
Быстро на больших таблицах, но создаёт новый объект — старые ссылки на строки обнуляются.
Удаление строк из табличной части документа
Табличная часть объекта поддерживает те же методы Удалить() и Количество(), поэтому обратный цикл работает без изменений. Отличие в том, что изменения существуют только в памяти до вызова метода Записать() у объекта.
Если документ проведён, запись после изменения табличной части потянет перепроведение и пересчёт движений. Для массовых обработок это может занять заметное время и заблокировать данные для других пользователей. В клиент-серверном режиме такие операции лучше выполнять на сервере и по возможности вне пиковой нагрузки.
Для управляемых форм есть нюанс: если таблица отображается на форме как данные формы коллекция, удаление программным способом выполняется через объект, а форма обновится после обращения к данным. Не удаляйте строки напрямую из коллекции формы, минуя объект, если дальше планируется запись — легко получить рассинхронизацию.
Типичные ошибки и как их избежать
Самая частая ошибка — удаление внутри цикла «Для Каждого Строка Из Таблицы». Платформа может не выдать ошибку сразу, но часть строк будет пропущена, и результат окажется непредсказуемым. Второй типовой сценарий — удаление по индексу в прямом цикле: после первого удаления все последующие индексы смещаются на единицу.
Ещё одна проблема — попытка удалить строку, которая уже была удалена ранее по ссылке из другого массива. Платформа выбросит исключение о том, что строка не принадлежит таблице. Если массивы строк собираются из разных отборов, перед удалением стоит проверять принадлежность через Индекс() — метод вернёт -1 для чужой строки.
Как проверить, что удаление прошло корректно
Минимальная проверка — сравнить количество строк до и после операции. Разница должна точно совпадать с числом строк, подлежавших удалению. Если вы удаляли по массиву из НайтиСтроки, сравните разницу с размером этого массива.
Для контроля по содержимому после удаления выполните повторный НайтиСтроки с тем же отбором: результат должен быть пустым массивом. Это подтверждает, что ни одна целевая строка не осталась, включая возможные дубли по условию отбора.
Если изменялась табличная часть документа, дополнительно проверьте итоговые суммы по колонкам (метод Итог()) и, при проведённом документе, движения по регистрам после записи.
Как проверить результат
Разница равна числу удаляемых строк
Разница меньше — часть строк пропущена из-за сдвига индексов
Возвращается пустой массив
Строки находятся — условие удаления отработало не полностью
Итог уменьшился на сумму удалённых строк
Итог не изменился или изменился непредсказуемо
Частые вопросы
Можно ли удалить массив строк одним методом без цикла?
Отдельного метода «удалить массив» в платформе нет. Одно действие без цикла возможно только для полной очистки таблицы — метод Очистить(). Для выборочного удаления всегда нужен либо перебор, либо пересоздание таблицы через запрос или Скопировать() с отбором.
Почему после удаления в цикле остаются строки, которые должны были удалиться?
Почти всегда причина в прямом переборе: при удалении текущей строки следующая сдвигается на её место, а итератор переходит дальше, пропуская её. Решение — обратный цикл по индексу или предварительный сбор строк в массив через НайтиСтроки.
Что быстрее для большой таблицы — цикл или запрос?
Для таблиц с сотнями строк разница незаметна. На больших объёмах запрос с выгрузкой результата обычно быстрее, потому что фильтрация выполняется пакетно, а не поэлементно. Точные цифры зависят от конфигурации и сервера, поэтому на критичных обработках стоит замерить оба варианта на своих данных.
Как удалить строки по условию «не равно» или «больше»?
НайтиСтроки такие условия не поддерживает — там только равенство. Используйте обратный цикл с проверкой условия внутри или запрос с произвольным условием в секции ГДЕ.
Удалятся ли строки из базы данных сразу после Удалить()?
Нет. Для таблицы значений вопрос неактуален — она существует только в памяти. Для табличной части объекта изменения попадут в базу только после вызова Записать() у объекта. До записи достаточно закрыть объект без сохранения, чтобы отменить удаление.
Как понять, принадлежит ли строка конкретной таблице перед удалением?
Вызовите у таблицы метод Индекс(Строка). Если строка принадлежит таблице, вернётся её индекс (от 0 и выше), если нет — значение -1. Это удобная защита при удалении строк, собранных из разных источников.
Что важно запомнить
Безопасные способы удалить массив строк из таблицы 1С — обратный цикл по индексу или перебор массива, полученного через НайтиСтроки, с удалением по объекту строки. Для больших таблиц эффективнее пересоздание через запрос. После работы сверяйте количество строк и повторным отбором убеждайтесь, что целевых строк не осталось.