Удаление и очистка данных таблиц в 1С: интерфейс и встроенный язык

· 9 мин

Содержание

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

Ниже — конкретные приёмы для платформы 8.3 (интерфейс «Такси»): что делать руками, а что кодом, как не оставить битых ссылок и как справиться с массовым удалением, когда строк десятки тысяч.

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

Табличная часть — это коллекция строк внутри объекта (Товары, Начисления, Материалы). В коде она чистится одной строкой:

Объект.Товары.Очистить();

После Очистить() в коллекции ноль строк. Изменения попадут в базу только после записи объекта — Объект.Записать(). Если вы в модуле формы, не забудьте перенести значение в объект или работать через Объект формы напрямую.

Удалить не все строки, а по условию — обходите коллекцию с конца. Если идти с начала и удалять строки, индексы сдвигаются и часть строк проскочит:

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

Нужно удалить одну известную строку — передайте в Удалить() саму строку или её индекс: Объект.Товары.Удалить(СтрокаТЧ).

Вручную, из открытого документа: встаньте в таблицу, выделите строки (Ctrl+A — все) и нажмите клавишу Delete или команду удаления строки в командной панели табличной части. Это правит только открытый документ; после закрытия проведите или запишите его.

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

Отдельно стоит различать табличную часть и таблицу значений в памяти — у разработчиков «очистить таблицу» часто означает именно её. ТаблицаЗначений живёт в памяти, в базе её нет, поэтому запись объекта тут ни при чём:

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура");
ТЗ.Колонки.Добавить("Количество");
// ... заполнили ...
ТЗ.Очистить(); // строки удалены, колонки остались

Очистить() убирает строки, но сохраняет структуру колонок. Если нужно сбросить таблицу целиком вместе с колонками — проще создать её заново через Новый ТаблицаЗначений. Так же работает ДеревоЗначений и СписокЗначений.

Временную таблицу в запросе чистят иначе — через менеджер временных таблиц:

МенеджерВТ.Таблицы.Найти("ВТ_Остатки").Уничтожить();

Либо уничтожают весь менеджер временных таблиц методом Закрыть() — тогда освобождаются все временные таблицы пакета.

Пометка на удаление элементов справочников и документов

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

Порядок действий:

  1. В списке выделите элементы (можно несколько через Ctrl или Shift).
  2. Нажмите Delete или команду пометки на удаление в командной панели списка — у строки появится перечёркнутый значок.
  3. Запустите удаление: Администрирование → Обслуживание → Удаление помеченных объектов.
  4. Программа проверит ссылки. Объекты без ссылок удалятся, по остальным покажет, где они используются.

Снять пометку — та же команда «Пометить на удаление» повторно: она работает как переключатель.

«Удаление помеченных объектов» на время работы может требовать, чтобы в базе не меняли помеченные данные. Запускайте в нерабочее время или предупредите пользователей — иначе часть объектов не удалится из-за блокировок.

Программно пометка ставится так:

ОбъектСсылка = Справочники.Номенклатура.НайтиПоКоду("00-0001");
Объект = ОбъектСсылка.ПолучитьОбъект();
Объект.УстановитьПометкуУдаления(Истина);

Параметр Истина ставит пометку, Ложь — снимает. Метод сам запишет объект.

Непосредственное удаление кодом: метод Удалить()

Если нужно удалить объект сразу, минуя пометку, есть метод Удалить():

Объект = ОбъектСсылка.ПолучитьОбъект();
Объект.Удалить();

Это непосредственное удаление: платформа не проверяет, ссылается ли кто-то на объект. Удалите номенклатуру, которая стоит в проведённых документах, — и в этих документах останется «битая ссылка» (<Объект не найден>).

Поэтому непосредственное удаление применяют только когда вы точно знаете, что ссылок нет: разовая чистка тестовых данных, объекты, созданные только что в той же транзакции, технологические справочники. В рабочей базе по умолчанию используйте связку «пометка + обработка удаления».

Сравнение двух способов:

СпособПроверка ссылокКогда применятьРиск
Пометка + «Удаление помеченных»Да, автоматическиРабочая база, обычная чисткаМинимальный
Удалить() напрямуюНетТестовые данные, гарантированно без ссылокБитые ссылки

Массовое удаление по выборке запроса

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

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |    Док.Ссылка КАК Ссылка
    |ИЗ
    |    Документ.ЗаказПокупателя КАК Док
    |ГДЕ
    |    Док.Дата < &ГраницаДаты
    |    И Док.Проведён = ЛОЖЬ";
Запрос.УстановитьПараметр("ГраницаДаты", '20240101');

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Объект = Выборка.Ссылка.ПолучитьОбъект();
    Объект.УстановитьПометкуУдаления(Истина);
КонецЦикла;

Здесь запрос отбирает непроведённые заказы старше нужной даты и ставит им пометку. Дальше их удалит штатная обработка — с проверкой ссылок.

Запрос не держит объекты в памяти все сразу: Выбрать() отдаёт их по одному. Для сотен тысяч строк это важно — иначе рискуете упереться в память.

Если данные гарантированно без ссылок и вы хотите удалить сразу, замените УстановитьПометкуУдаления(Истина) на Объект.Удалить() — но помните про риск из предыдущего раздела.

Очистка движений по регистрам

Движения регистров (накопления, сведений, бухгалтерии) чистятся не через Удалить(), а записью набора записей. Пустой набор при записи стирает все движения по отбору.

Удалить движения конкретного документа-регистратора:

НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Записать(); // набор пустой — движения удаляются

Ключевой момент: мы не читали набор из базы (Прочитать() не вызывали), поэтому он пуст. При Записать() с режимом замены (по умолчанию) платформа заменяет все записи по отбору на содержимое набора — то есть на пустоту. Движения удаляются.

Тот же приём для регистра сведений — если это регистр, подчинённый регистратору. Для независимого регистра сведений отбор ставят по его измерениям:

НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(НоменклатураСсылка);
НаборЗаписей.Записать();

Чтобы очистить регистр целиком — не по одному документу, а все записи — создайте набор без отбора (или сбросьте отбор) и запишите его пустым. Для независимого регистра сведений это сотрёт всю таблицу:

НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Записать(); // отбор не задан — очищается весь регистр

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

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

Отменить проведение документа кодом (движения при этом очистятся штатно):

ДокОбъект = ДокументСсылка.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);

Транзакции и блокировки при удалении

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

НачатьТранзакцию();
Попытка
    Объект1.Удалить();
    Объект2.Удалить();
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;

Если на любой строке возникнет ошибка, ОтменитьТранзакцию() откатит всё, что успели сделать внутри. Без транзакции первый объект удалится, а второй — нет, и база останется в половинчатом состоянии.

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

Про блокировки стоит знать два момента:

  • 🔒 Когда вы изменяете или удаляете объект, платформа ставит на него блокировку до конца транзакции. Другой сеанс, который тронет тот же объект, будет ждать или получит ошибку «Конфликт блокировок».
  • ⏱ Длинная транзакция (удаляем тысячи строк в одной) держит блокировки всё это время и копит данные для отката. Это тормозит других пользователей и раздувает журнал транзакций СУБД.

Поэтому массовое удаление дробят на порции — об этом ниже.

Оптимизация массового удаления больших объёмов

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

  1. Порциями, не всё одной транзакцией. Удаляйте по 500–1000 объектов за транзакцию, затем фиксируйте и начинайте следующую. Короткие транзакции не держат блокировки долго и не раздувают журнал СУБД.
  2. Монопольный режим для разовой чистки. Если база на обслуживании и пользователей нет, установка монопольного режима (УстановитьМонопольныйРежим(Истина)) заметно ускоряет удаление: платформе не нужно разбираться с чужими блокировками. Только убедитесь, что в базе действительно никого нет.
  3. «Удаление помеченных объектов» умеет работать в фоне. В списке объектов на удаление можно сначала получить полный список, а саму чистку запустить отдельно — это разводит тяжёлую проверку ссылок и удаление по времени.
  4. Не логируйте лишнее. Массовая чистка пишет кучу записей в журнал регистрации. Для разовой технологической операции это пустая нагрузка — по возможности планируйте её на окно обслуживания.
  5. Собирайте ссылки в массив, удаляйте отдельным проходом. Сначала запросом получите все ссылки в один массив, закройте выборку, а потом удаляйте по нему. Так удаление не держит открытым результат запроса всё время работы.

Пример удаления порциями:

Выборка = Запрос.Выполнить().Выбрать();
Счётчик = 0;
НачатьТранзакцию();
Пока Выборка.Следующий() Цикл
    Выборка.Ссылка.ПолучитьОбъект().Удалить();
    Счётчик = Счётчик + 1;
    Если Счётчик % 1000 = 0 Тогда
        ЗафиксироватьТранзакцию();
        НачатьТранзакцию();
    КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();

Обработку, которая удаляет данные пачками, тестируйте на копии базы. Перед запуском на рабочей — резервная копия обязательна: откатить массовое удаление потом нельзя.

Перед массовым удалением проверьте
Выполнено: 0 / 5

Частые ошибки и как их избежать

Четыре промаха, на которых спотыкаются чаще всего:

  • ❌ Цикл по табличной части с начала при удалении строк. Индексы сдвигаются, часть строк остаётся. Идите с конца (По 0 Шаг -1).
  • ❌ Очистить() без записи объекта. Строки пропали в памяти, но в базе остались — забыли вызвать Записать(). В интерфейсе то же самое: правки надо записать или провести.
  • ❌ Удалить() вместо пометки в рабочей базе. Получаете битые ссылки в документах. Если не уверены в отсутствии ссылок — только пометка и штатная обработка.
  • ❌ Чистка движений регистра под проведённым документом. Учёт рассогласуется. Правильнее отменить проведение или перепровести документ .

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

Чем «пометка на удаление» отличается от удаления?
Пометка только помечает объект (ставит перечёркнутый значок), данные остаются в базе. Фактически объект удаляет обработка «Удаление помеченных объектов» — и только если на него никто не ссылается.
Как удалить сразу все строки табличной части в коде?
Методом Очистить(): Объект.Товары.Очистить(). После этого запишите объект. Удалить строки по условию — цикл с конца коллекции с методом Удалить().
Можно ли восстановить удалённые объекты?
Непосредственно удалённые (Удалить() или после «Удаления помеченных») — нет, только из резервной копии базы. Поэтому перед массовой чисткой делают бэкап. Пока объект лишь помечен на удаление, пометку легко снять.
Почему «Удаление помеченных объектов» не удаляет объект?
Чаще всего на него ещё есть ссылки из других документов или справочников — обработка покажет, где именно. Удалите или перенастройте эти ссылки, затем повторите удаление.
Как очистить движения документа по регистру?
Создайте набор записей регистра, установите отбор по регистратору (документу) и запишите пустой набор — движения удалятся. Но обычно надёжнее отменить проведение документа штатно.