К статье
Практический материал

Разработка и Конфигурация · 9 мин

1С: как удалить строку из табличной части по условию

Как программно удалить строки из табличной части документа в 1С по условию: методы НайтиСтроки, обход с конца, примеры кода, типичные ошибки и проверка результата.

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

Главная сложность заключается в том, что нельзя удалять строки прямо в цикле «Для Каждого»: коллекция изменяется во время обхода, индексы сдвигаются, и часть строк пропускается либо возникает ошибка. Ниже разобраны три рабочих способа, которые безопасно решают эту задачу на управляемых и обычных формах.

Все примеры применимы к типовым и самописным конфигурациям на платформе 1С:Предприятие 8.3, как в серверном, так и в клиентском контексте — с учётом ограничений, которые описаны отдельно.

Способ 1. НайтиСтроки и последующее удаление

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

Отбор = Новый Структура("Количество", 0);

НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Для Каждого СтрокаТовара Из НайденныеСтроки Цикл

Объект.Товары.Удалить(СтрокаТовара);

КонецЦикла;

Этот способ удобен, когда условие простое и выражается равенством значений колонок: конкретная номенклатура, нулевое количество, заданный склад. Если условие сложнее (например, «сумма меньше 100» или сравнение дат), НайтиСтроки не подойдёт — структура отбора поддерживает только сравнение на равенство.

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

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

Способ 2. Обход коллекции с конца по индексу

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

КоличествоСтрок = Объект.Товары.Количество();

Для Индекс = 1 По КоличествоСтрок Цикл

ТекущаяСтрока = Объект.Товары[КоличествоСтрок - Индекс];

Если ТекущаяСтрока.Сумма < 100 Тогда

Объект.Товары.Удалить(ТекущаяСтрока);

КонецЕсли;

КонецЦикла;

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

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

Способ 3. Цикл «Пока» с ручным управлением индексом

Альтернатива обходу с конца — идти с начала, но увеличивать индекс только тогда, когда строка не была удалена. Если строка удалена, следующая «подтягивается» на её место, и индекс увеличивать нельзя.

Индекс = 0;

Пока Индекс < Объект.Товары.Количество() Цикл

СтрокаТовара = Объект.Товары[Индекс];

Если СтрокаТовара.Отменено Тогда

Объект.Товары.Удалить(Индекс);

Иначе

Индекс = Индекс + 1;

КонецЕсли;

КонецЦикла;

Количество строк в условии цикла вычисляется на каждой итерации заново — это важно, потому что коллекция уменьшается. Такой вариант наглядно показывает логику «удалил — остался на месте, не удалил — пошёл дальше» и часто используется в типовых конфигурациях.

Сравнение способов

НайтиСтроки + Удалить

Подходит для простых условий на равенство. Код короткий и читаемый. Не работает со сравнениями «больше/меньше».

Обход с конца по индексу

Универсален для любых условий, один проход по коллекции. Требует аккуратности с нумерацией с нуля.

Цикл Пока с ручным индексом

Гибкая логика, легко добавить подсчёт удалённых строк. Чуть сложнее для восприятия.

Удаление на форме и модифицированность объекта

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

&НаКлиенте

Процедура УдалитьНулевыеСтроки(Команда)

УдалитьНулевыеСтрокиНаСервере();

Модифицированность = Истина;

КонецПроцедуры

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

Проведённый документ и права доступа

Изменить табличную часть проведённого документа программно можно, но при записи в режиме РежимЗаписиДокумента.Проведение документ будет перепроведён, и движения по регистрам пересчитаются. Если нужно только сохранить изменения без перепроведения, используйте РежимЗаписиДокумента.Запись — однако тогда движения перестанут соответствовать данным документа, что обычно недопустимо для учёта.

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

Типичные ошибки при удалении строк

Самая частая ошибка — удаление внутри цикла Для Каждого по самой коллекции. Платформа при этом либо пропускает строки, либо поведение становится непредсказуемым, потому что внутренний итератор сбивается при изменении коллекции. Такой код иногда «работает» на маленьких табличных частях и ломается на больших, что затрудняет поиск причины.

Вторая распространённая проблема — забытая запись объекта после удаления в серверной обработке: код отрабатывает без ошибок, но в базе ничего не меняется. Третья — сравнение ссылочных полей со строковым представлением вместо ссылки: отбор по НайтиСтроки в этом случае ничего не находит.

Типичные ошибки
01
Удаление строк в цикле «Для Каждого» по той же коллекции — часть строк пропускается, условие срабатывает не для всех позиций.
02
Отсутствие Записать() после изменений в серверной обработке — документ в базе остаётся прежним.
03
Отбор строкового представления вместо ссылки в НайтиСтроки — массив найденных строк пустой, удаление не происходит.
04
Индексация с единицы вместо нуля при обходе по индексу — ошибка «Индекс находится за границами массива».

Проверка результата после удаления

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

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

Контрольные точки

Как проверить результат

Количество строк после обработки
Норма

Равно исходному минус число строк, подходящих под условие

Тревожный признак

Строк больше или меньше ожидаемого — условие или цикл работают неверно

Сообщение о числе удалённых строк
Норма

Число соответствует подсчёту по отбору вручную

Тревожный признак

Ноль при наличии подходящих строк — ошибка в условии отбора

Состояние документа в базе
Норма

Документ записан, движения соответствуют табличной части

Тревожный признак

Изменения видны только в форме и пропадают после закрытия

FAQ

Можно ли удалить строки табличной части запросом?

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

Как удалить все строки табличной части без условия?

Используйте метод Очистить(): Объект.Товары.Очистить(). Это быстрее и проще, чем обход с удалением по одной строке.

Почему НайтиСтроки возвращает пустой массив, хотя подходящие строки есть?

Чаще всего причина в несовпадении типов: в отборе передано строковое представление вместо ссылки, число в другом формате или лишние пробелы в строковом значении. Проверьте тип и значение поля в отладчике и передавайте в структуру отбора значение ровно того же типа.

Работает ли НайтиСтроки на клиенте в управляемой форме?

Да, для данных формы типа «ДанныеФормыКоллекция» доступны методы НайтиСтроки и Удалить на клиенте, поэтому простую очистку можно выполнять без вызова сервера. Сложная логика с обращением к базе потребует серверного вызова.

Что произойдёт с нумерацией строк после удаления?

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

Как удалить строки из табличной части нескольких документов сразу?

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

Итог

Что важно запомнить

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