Удаление строк из табличной части документа в 1С 8.3: вручную и программно

· 9 мин

Содержание

Чтобы удалить строку табличной части в 1С 8.3, выделите её в таблице документа и нажмите Delete или выберите Удалить в контекстном меню (правая кнопка мыши). Затем запишите документ, а если он был проведён — перепроведите. В коде то же самое делает метод Удалить() у табличной части: Документ.Товары.Удалить(Строка).

Типичная ситуация: в реализацию подбором попали лишние позиции, или обработка загрузки из Excel создала пустые строки с нулевым количеством. Руками удалить пару строк — секунда. А вот программно убрать сотню строк по условию так, чтобы цикл не пропустил половину и не упал с ошибкой индекса, умеет не каждый. Разберём оба пути: интерфейс пользователя и встроенный язык.

Удаление строк вручную в режиме 1С:Предприятие

Табличная часть — это таблица внутри документа или справочника: «Товары», «Услуги», «Сотрудники», «Начисления». Строки в ней удаляются сразу, без пометки. Пометка на удаление бывает только у самих документов и элементов справочников, у строк её нет.

Одна строка

  1. Откройте документ.
  2. Щёлкните по нужной строке таблицы, чтобы она стала текущей.
  3. Нажмите Delete на клавиатуре. Второй вариант — правая кнопка мыши → Удалить. Третий — кнопка Ещё над таблицей → Удалить.
  4. Нажмите Записать или Провести и закрыть.

Номера строк (колонка N) перенумеруются автоматически. Пропусков в нумерации не останется.

Несколько строк сразу

  • 🖱️ Подряд идущие — щёлкните первую строку, зажмите Shift и щёлкните последнюю.
  • 🖱️ Вразнобой — зажмите Ctrl и щёлкайте по нужным строкам.
  • ⌨️ После выделения нажмите Delete — удалятся все выделенные строки.

Если Shift и Ctrl не выделяют несколько строк, у этой таблицы в форме отключён множественный выбор. Такое бывает в доработанных формах. Тогда удаляйте по одной или попросите программиста включить режим выделения.

Отмены удаления строки (Ctrl+Z) в таблице документа нет. Если удалили не то, закройте документ без сохранения: на вопрос «Данные были изменены. Сохранить изменения?» ответьте Нет. Документ вернётся к последнему записанному состоянию.

Когда кнопка «Удалить» неактивна

  • 🔒 Документ открыт только для просмотра: закрыт период запретом изменения данных или у пользователя нет права на изменение.
  • 🔒 Таблица в форме заблокирована от редактирования настройками или доработкой.
  • 🔒 Документ создан на основании или загружен через обмен, и форма запрещает правку отдельных частей.

Проверить права и дату запрета изменения может администратор базы. Пользователю обходить запрет не нужно: удаление строк в закрытом периоде меняет уже сданную отчётность.

Метод Удалить() во встроенном языке

В коде у табличной части объекта (тип ТабличнаяЧасть) есть метод Удалить(). Он принимает либо саму строку, либо её индекс. Индексы считаются с нуля: первая строка — [0], хотя в колонке N у неё стоит 1.

ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// удалить строку по индексу: вторая строка таблицы
ДокументОбъект.Товары.Удалить(1);

// удалить конкретную строку
Строка = ДокументОбъект.Товары[0];
ДокументОбъект.Товары.Удалить(Строка);

// очистить табличную часть целиком
ДокументОбъект.Товары.Очистить();

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

Если ДокументОбъект.Проведен Тогда
    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Иначе
    ДокументОбъект.Записать();
КонецЕсли;

Удаление по значению реквизита

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

Отбор = Новый Структура("Номенклатура", УдаляемаяНоменклатура);
НайденныеСтроки = ДокументОбъект.Товары.НайтиСтроки(Отбор);

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

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

Запросом строки не удалить

Язык запросов 1С только читает данные. Удалить строку табличной части запросом нельзя. Запросом можно найти документы, в которых есть лишние строки, а удалять — через объект: ПолучитьОбъект() → Удалить() → Записать().

Удаление строк по условию: обратный цикл

Главная ловушка — удалять строки в прямом цикле Для Каждого по той же табличной части. После удаления строка ниже сдвигается на её место, и цикл её перепрыгивает. Две подряд пустые строки — одна останется.

Правильно идти с конца. Количество строк берём один раз до цикла, а индекс считаем от него:

Всего = ДокументОбъект.Товары.Количество();

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

Проверим на примере из 5 строк, где пустые — 2-я и 3-я (индексы 1 и 2). Цикл смотрит индексы 4, 3, 2, 1, 0. Удаляется индекс 2, затем индекс 1. Строки с меньшими индексами при удалении не сдвигаются, поэтому обе пустые строки уходят, а остальные три остаются.

Второй безопасный приём — сначала собрать удаляемые строки в массив, потом удалить их отдельным циклом:

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

Для Каждого Строка Из КУдалению Цикл
    ДокументОбъект.Товары.Удалить(Строка);
КонецЦикла;
СпособКогда подходитРиск
Удалить(Индекс) / Удалить(Строка)одна известная строкаошибка, если индекс за пределами таблицы
НайтиСтроки() + циклотбор по точному значениюнет, массив отдельный
Обратный цикл по индексулюбое условиеошибка, если границу пересчитывать внутри цикла
Массив «к удалению»любое условие, читаемый кодлишний проход, на больших таблицах заметен
Очистить()убрать всё и заполнить зановопотеря строк, которые хотели оставить

Строки табличной части в управляемой форме

В управляемой форме код работает не с объектом, а с его данными на форме: Объект.Товары имеет тип ДанныеФормыКоллекция. Метод Удалить() у неё тоже есть и доступен прямо на клиенте.

Текущая строка

&НаКлиенте
Процедура УдалитьТекущуюСтроку(Команда)
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    Объект.Товары.Удалить(ТекущиеДанные);
    Модифицированность = Истина;
КонецПроцедуры

Проверка на Неопределено обязательна: если в таблице нет строк или курсор не стоит ни на одной, без неё будет ошибка.

Модифицированность = Истина нужна потому, что изменение данных из кода не помечает форму как изменённую. Без этой строки пользователь закроет форму, программа не спросит про сохранение, и удаление потеряется.

Выделенные строки

Свойство ВыделенныеСтроки элемента таблицы возвращает массив идентификаторов, а не самих строк. Этот массив меняется по ходу удаления, поэтому сначала переводим идентификаторы в строки, потом удаляем:

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

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

    Модифицированность = Истина;
КонецПроцедуры

Запрет удаления отдельных строк

Если некоторые строки трогать нельзя (например, строка уже согласована), используйте событие ПередУдалением элемента формы «Таблица». Параметр Отказ = Истина отменяет удаление, сделанное пользователем кнопкой или клавишей:

&НаКлиенте
Процедура ТоварыПередУдалением(Элемент, Отказ)
    Если Элемент.ТекущиеДанные.Согласовано Тогда
        Отказ = Истина;
        ПоказатьПредупреждение(, "Согласованную строку удалить нельзя.");
    КонецЕсли;
КонецПроцедуры

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

В типовые формы код лучше не вписывать напрямую. Добавьте команду и обработчики через расширение конфигурации: при обновлении типовой ваша доработка не потеряется.

Как удалить сами документы, а не строки

Иногда запрос «удалить строку» на деле значит «убрать лишний документ из списка». Это другая операция, в два шага:

  1. В списке документов выделите строку документа и нажмите Delete. Документ получит пометку на удаление: он перечёркнут, движения проведения снимаются.
  2. Физически удалите помеченные объекты обработкой «Удаление помеченных объектов». В БП 3.0 она находится в разделе Администрирование → Обслуживание, группа «Корректировка данных».

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

Перед удалением помеченных объектов сделайте резервную копию базы. Физическое удаление необратимо. В файловом варианте во время обработки другим пользователям лучше в базе не работать: она может потребовать монопольный режим, и тогда их сеансы придётся завершить.

К строкам табличной части эта обработка отношения не имеет. Строка, удалённая из таблицы и записанная в документе, исчезает сразу, восстановить её можно только из резервной копии или по истории версий, если она включена.

Скорость: тысячи строк и массовая чистка

На таблице из 30–50 строк любой способ работает мгновенно. Разница появляется на тысячах строк: загрузка прайса, инвентаризация склада, ведомость на весь штат.

Что тормозит

  • 🐢 Серверные вызовы в цикле. Цикл на клиенте, который на каждой строке вызывает процедуру &НаСервере, гоняет данные по сети туда-обратно. 2 000 строк — 2 000 вызовов.
  • 🐢 Пересчёт на каждой итерации. Обращение к Количество() внутри условия, пересчёт итогов формы после каждого удаления.
  • 🐢 Удаление из начала таблицы. При удалении первой строки сдвигаются все последующие. Удаление с конца дешевле.

Как ускорить

Перенесите всю чистку в одну серверную процедуру формы. Клиент вызывает её один раз:

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

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

ТЗ = ДокументОбъект.Товары.Выгрузить();

Оставить = Новый Массив;
Для Каждого Строка Из ТЗ Цикл
    Если Строка.Количество <> 0 Тогда
        Оставить.Добавить(Строка);
    КонецЕсли;
КонецЦикла;

ДокументОбъект.Товары.Загрузить(ТЗ.Скопировать(Оставить));

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

Если обрабатываете много документов, не держите их все в одной транзакции. Записывайте каждый документ отдельно и выводите в журнал, какие обработаны: при ошибке на 300-м документе первые 299 останутся записанными, и повторный запуск продолжит с места сбоя.

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

Диагностика: выберите симптом

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

Можно ли удалить строку из проведённого документа?
Да. Удалите строку и перепроведите документ, иначе в регистрах останутся движения по удалённой позиции. В закрытом периоде этому помешает дата запрета изменения.
Чем удаление строк отличается от метода Очистить()?
Удалить() убирает одну строку, Очистить() — все сразу. Очистку применяют, когда табличную часть заполняют заново, например повторным подбором или загрузкой.
Как удалить строки в табличной части справочника?
Так же, как в документе: Delete в форме элемента или Удалить() у объекта справочника, затем Записать(). Перепроводить ничего не нужно.
Как восстановить случайно удалённую строку?
Если документ ещё не записан — закройте его без сохранения. Если записан — только из резервной копии или из истории изменений, если версионирование объектов включено в настройках.
Почему после удаления строк не пересчиталась сумма документа?
Итог по табличной части в форме обычно пересчитывается обработчиками. При удалении из кода вызовите процедуру пересчёта сами или поместите её в событие ПослеУдаления таблицы.