Удаление строк из табличной части документа в 1С 8.3: вручную и программно
Содержание
Чтобы удалить строку
табличной части в 1С 8.3, выделите её в таблице документа и нажмите Delete или выберите Удалить в контекстном меню (правая кнопка мыши). Затем запишите документ, а если он был проведён — перепроведите. В коде то же самое делает метод Удалить() у табличной части: Документ.Товары.Удалить(Строка).
Типичная ситуация: в реализацию подбором попали лишние позиции, или обработка загрузки из Excel создала пустые строки с нулевым количеством. Руками удалить пару строк — секунда. А вот программно убрать сотню строк по условию так, чтобы цикл не пропустил половину и не упал с ошибкой индекса, умеет не каждый. Разберём оба пути: интерфейс пользователя и встроенный язык.
Удаление строк вручную в режиме 1С:Предприятие
Табличная часть — это таблица внутри документа или справочника: «Товары», «Услуги», «Сотрудники», «Начисления». Строки в ней удаляются сразу, без пометки. Пометка на удаление бывает только у самих документов и элементов справочников, у строк её нет.
Одна строка
- Откройте документ.
- Щёлкните по нужной строке таблицы, чтобы она стала текущей.
- Нажмите
Deleteна клавиатуре. Второй вариант — правая кнопка мыши →Удалить. Третий — кнопкаЕщёнад таблицей →Удалить. - Нажмите
ЗаписатьилиПровести и закрыть.
Номера строк (колонка 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 Тогда
КУдалению.Добавить(Строка);
КонецЕсли;
КонецЦикла;
Для Каждого Строка Из КУдалению Цикл
ДокументОбъект.Товары.Удалить(Строка);
КонецЦикла;
| Способ | Когда подходит | Риск |
|---|---|---|
Удалить(Индекс) / Удалить(Строка) | одна известная строка | ошибка, если индекс за пределами таблицы |
НайтиСтроки() + цикл | отбор по точному значению | нет, массив отдельный |
| Обратный цикл по индексу | любое условие | ошибка, если границу пересчитывать внутри цикла |
| Массив «к удалению» | любое условие, читаемый код | лишний проход, на больших таблицах заметен |
Очистить() | убрать всё и заполнить заново | потеря строк, которые хотели оставить |
Строки табличной части в управляемой форме
В управляемой форме код работает не с объектом, а с его данными на форме: Объект.Товары имеет тип ДанныеФормыКоллекция. Метод Удалить() у неё тоже есть и доступен прямо на клиенте.
Текущая строка
&НаКлиенте
Процедура УдалитьТекущуюСтроку(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Объект.Товары.Удалить(ТекущиеДанные);
Модифицированность = Истина;
КонецПроцедуры
Проверка на Неопределено обязательна: если в таблице нет строк или курсор не стоит ни на одной, без неё будет ошибка.
Модифицированность = Истина нужна потому, что изменение данных из кода не помечает форму как изменённую. Без этой строки пользователь закроет форму, программа не спросит про сохранение, и удаление потеряется.
Выделенные строки
Свойство ВыделенныеСтроки элемента таблицы возвращает массив идентификаторов, а не самих строк. Этот массив меняется по ходу удаления, поэтому сначала переводим идентификаторы в строки, потом удаляем:
&НаКлиенте
Процедура УдалитьВыделенные(Команда)
Удаляемые = Новый Массив;
Для Каждого Идентификатор Из Элементы.Товары.ВыделенныеСтроки Цикл
Удаляемые.Добавить(Объект.Товары.НайтиПоИдентификатору(Идентификатор));
КонецЦикла;
Для Каждого Строка Из Удаляемые Цикл
Объект.Товары.Удалить(Строка);
КонецЦикла;
Модифицированность = Истина;
КонецПроцедуры
Запрет удаления отдельных строк
Если некоторые строки трогать нельзя (например, строка уже согласована), используйте событие ПередУдалением элемента формы «Таблица». Параметр Отказ = Истина отменяет удаление, сделанное пользователем кнопкой или клавишей:
&НаКлиенте
Процедура ТоварыПередУдалением(Элемент, Отказ)
Если Элемент.ТекущиеДанные.Согласовано Тогда
Отказ = Истина;
ПоказатьПредупреждение(, "Согласованную строку удалить нельзя.");
КонецЕсли;
КонецПроцедуры
Здесь Согласовано — реквизит табличной части, который вы добавили сами. Пересчёт итогов после удаления удобно делать в событии ПослеУдаления.
В типовые формы код лучше не вписывать напрямую. Добавьте команду и обработчики через расширение конфигурации: при обновлении типовой ваша доработка не потеряется.
Как удалить сами документы, а не строки
Иногда запрос «удалить строку» на деле значит «убрать лишний документ из списка». Это другая операция, в два шага:
- В списке документов выделите строку документа и нажмите
Delete. Документ получит пометку на удаление: он перечёркнут, движения проведения снимаются. - Физически удалите помеченные объекты обработкой «Удаление помеченных объектов». В БП 3.0 она находится в разделе
Администрирование → Обслуживание, группа «Корректировка данных».
Обработка проверяет ссылки. Если помеченный документ где-то используется (например, на него ссылается документ-основание), он не удалится, и программа покажет, где он упоминается.
Перед удалением помеченных объектов сделайте резервную копию базы. Физическое удаление необратимо. В файловом варианте во время обработки другим пользователям лучше в базе не работать: она может потребовать монопольный режим, и тогда их сеансы придётся завершить.
К строкам табличной части эта обработка отношения не имеет. Строка, удалённая из таблицы и записанная в документе, исчезает сразу, восстановить её можно только из резервной копии или по истории версий, если она включена.
Скорость: тысячи строк и массовая чистка
На таблице из 30–50 строк любой способ работает мгновенно. Разница появляется на тысячах строк: загрузка прайса, инвентаризация склада, ведомость на весь штат.
Что тормозит
- 🐢 Серверные вызовы в цикле. Цикл на клиенте, который на каждой строке вызывает процедуру
&НаСервере, гоняет данные по сети туда-обратно. 2 000 строк — 2 000 вызовов. - 🐢 Пересчёт на каждой итерации. Обращение к
Количество()внутри условия, пересчёт итогов формы после каждого удаления. - 🐢 Удаление из начала таблицы. При удалении первой строки сдвигаются все последующие. Удаление с конца дешевле.
Как ускорить
Перенесите всю чистку в одну серверную процедуру формы. Клиент вызывает её один раз:
&НаСервере
Процедура УдалитьНулевыеСтрокиНаСервере()
Строки = Объект.Товары.НайтиСтроки(Новый Структура("Количество", 0));
Для Каждого Строка Из Строки Цикл
Объект.Товары.Удалить(Строка);
КонецЦикла;
КонецПроцедуры
Когда удалить нужно большую часть строк, быстрее не удалять, а пересобрать таблицу: выгрузить в таблицу значений, скопировать только нужные строки и загрузить обратно.
ТЗ = ДокументОбъект.Товары.Выгрузить();
Оставить = Новый Массив;
Для Каждого Строка Из ТЗ Цикл
Если Строка.Количество <> 0 Тогда
Оставить.Добавить(Строка);
КонецЕсли;
КонецЦикла;
ДокументОбъект.Товары.Загрузить(ТЗ.Скопировать(Оставить));
Загрузить() полностью заменяет содержимое табличной части, номера строк проставляются заново. Колонки в таблице значений должны совпадать с реквизитами табличной части: при Выгрузить() без параметров это так и есть.
Если обрабатываете много документов, не держите их все в одной транзакции. Записывайте каждый документ отдельно и выводите в журнал, какие обработаны: при ошибке на 300-м документе первые 299 останутся записанными, и повторный запуск продолжит с места сбоя.
Ошибки при удалении строк и что с ними делать
Для Каждого по той же табличной части: соседняя строка сдвигается и пропускается. Используйте НайтиСтроки(), массив к удалению или обратный цикл.Неопределено. Чаще всего ТекущиеДанные пусты: в таблице нет строк или ни одна не выбрана. Добавьте проверку на Неопределено.ПолучитьОбъект().Модифицированность = Истина или запишите объект явно.Частые вопросы
Можно ли удалить строку из проведённого документа?
Чем удаление строк отличается от метода Очистить()?
Удалить() убирает одну строку, Очистить() — все сразу. Очистку применяют, когда табличную часть заполняют заново, например повторным подбором или загрузкой.Как удалить строки в табличной части справочника?
Delete в форме элемента или Удалить() у объекта справочника, затем Записать(). Перепроводить ничего не нужно.Как восстановить случайно удалённую строку?
Почему после удаления строк не пересчиталась сумма документа?
ПослеУдаления таблицы.