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