Удаление записей подчинённого регистра сведений: вручную, кодом и порциями

· 10 мин

Содержание

Зависимый регистр сведений в 1С очищают через набор записей с отбором. Если регистр подчинён регистратору, ставят отбор по регистратору и записывают пустой набор Набор.Отбор.Регистратор.Установить(Документ) → Набор.Записать(). Если регистр независимый, но его измерение ссылается на справочник как ведущее, записи уйдут сами при удалении этого справочника. Вручную, в режиме Предприятия, получится удалить только записи независимого регистра: через Все функции → Регистры сведений.

Выбор способа зависит от того, от чего зависит регистр. От документа, от объекта в ведущем измерении или от логики другого регистра. Ошибка в выборе даёт два результата: проведённые документы без движений или «битые» ссылки <Объект не найден> в отчётах. Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конкретной конфигурации.

Какие регистры сведений считаются зависимыми

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

Под «зависимым» регистром на практике понимают один из трёх случаев:

  • 📄 Подчинён регистратору. Записи — это движения документа. У каждой строки есть поле Регистратор. Без документа записи не существуют.
  • 🔗 Есть ведущее измерение. Регистр независимый, но у измерения со ссылочным типом включено свойство «Ведущее». Записи живут, пока жив объект: удалили контрагента — удалились его строки.
  • 🧮 Логическая зависимость. Регистр заполняется кодом конфигурации по данным другого регистра или документов. Платформа о связи не знает. Связь держится только на алгоритме.

Проверить вид регистра можно в Конфигураторе: откройте ветку Регистры сведений, двойной щелчок по регистру, вкладка «Основные» — там «Режим записи» и «Периодичность». Свойство «Ведущее» смотрите в палитре свойств каждого измерения.

Если доступа к Конфигуратору нет, подсказку даёт форма списка. У подчинённого регистра в списке есть колонка «Регистратор», а добавить запись кнопкой «Создать» нельзя.

Чем отличается очистка при разных типах зависимости

Тип зависимости определяет три вещи: какой отбор обязателен, что произойдёт с документами и справочниками, что увидят отчёты после удаления.

Тип зависимостиКак удалить записиОбязательный отборРиск
Подчинение регистраторуОтменить проведение документа или записать пустой набор по регистраторуРегистраторДокумент остаётся проведённым без движений
Ведущее измерениеУдалить объект или набор с отбором по измерениюЛюбые измерения, можно без отбораОстанутся строки с другими объектами в неведущих измерениях
Логическая зависимостьНабор записей + повторное заполнение алгоритмом конфигурацииЛюбойРасхождение с исходным регистром

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

Для регистра с ведущим измерением удаление объекта платформа обрабатывает каскадно. Пометка на удаление записи не трогает. Строки исчезают только при окончательном удалении объекта.

Какой у вас регистр?

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

Без программирования доступно немногое. Но для разовой правки этого хватает.

Независимый регистр

  1. Включите команду «Все функции»: Главное меню → Сервис → Параметры, флажок «Отображать команду “Все функции”».
  2. Откройте Главное меню → Все функции → Регистры сведений и нужный регистр.
  3. Сузьте список до нужных строк: отбор по периоду или измерению задаётся через меню Ещё в командной панели списка.
  4. Выделите строки (Shift или Ctrl + щелчок) и нажмите Delete. Подтвердите удаление.

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

Перед удалением выгрузите базу в .dt или сделайте резервную копию SQL: восстановить строки регистра без копии нельзя.

Подчинённый регистр

Из формы списка подчинённого регистра строку не удалить: записи принадлежат документу. Варианты:

  • ↩️ отменить проведение документа (команда в списке документов или в форме документа);
  • ✏️ в типовых конфигурациях на базе БСП у многих документов есть флажок ручной корректировки движений — с ним строки правят прямо в документе;
  • 🗑️ пометить документ на удаление и удалить через Администрирование → Обслуживание → «Удаление помеченных объектов».

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

Регистр с ведущим измерением

Удалите объект, на который ссылается ведущее измерение. Сначала пометка на удаление, потом «Удаление помеченных объектов». Строки регистра с этим объектом удалятся вместе с ним.

Программная очистка: наборы записей и запросы

Основной инструмент — набор записей. Пустой набор, записанный с отбором, удаляет все строки под этот отбор. Код запускают на сервере: из внешней обработки (.epf) в процедуре с директивой &НаСервере.

Полная очистка независимого регистра

&НаСервере
Процедура ОчиститьРегистрПолностьюНаСервере()
    Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
    // Отбор не устанавливаем: пустой набор без отбора удаляет все записи
    Набор.Записать();
КонецПроцедуры

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

Удаление по измерению

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

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

Одна запись через менеджер записи

Менеджер = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
Менеджер.Период = ДатаЗаписи;
Менеджер.Контрагент = СсылкаНаКонтрагента;
Менеджер.Прочитать();
Если Менеджер.Выбран() Тогда
    Менеджер.Удалить();
КонецЕсли;

Менеджер записи есть только у независимых регистров. У подчинённого его нет.

Подчинённый регистр: удаление по регистраторам

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Т.Регистратор КАК Регистратор
|ИЗ
|    РегистрСведений.МойПодчиненныйРегистр КАК Т
|ГДЕ
|    Т.Период МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Начало", НачалоПериода);
Запрос.УстановитьПараметр("Конец", КонецПериода);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Набор = РегистрыСведений.МойПодчиненныйРегистр.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
    Набор.Записать();
КонецЦикла;

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

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

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

Периодический регистр: удаление старой истории

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

Пример. Цена товара записана 15.03 — 100 руб., 01.07 — 120 руб. Нужно удалить всё до 01.06. Если удалить запись от 15.03, то на 10.06 цена станет пустой. Хотя на эту дату действовала цена 100 руб.

Правильный порядок:

  1. Определите дату отсечения, например 01.06.
  2. Для каждой комбинации измерений запросом найдите последнюю запись до даты отсечения.
  3. Перенесите её значение на дату отсечения (запишите новую строку с периодом 01.06), если на эту дату записи ещё нет.
  4. Удалите все записи с периодом меньше даты отсечения.

Удаление по периоду для независимого регистра:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Т.Период КАК Период
|ИЗ
|    РегистрСведений.МойПериодическийРегистр КАК Т
|ГДЕ
|    Т.Период < &ДатаОтсечения";
Запрос.УстановитьПараметр("ДатаОтсечения", ДатаОтсечения);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Набор = РегистрыСведений.МойПериодическийРегистр.СоздатьНаборЗаписей();
    Набор.Отбор.Период.Установить(Выборка.Период);
    Набор.Записать();
КонецЦикла;

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

Для регистра с периодичностью «По позиции регистратора» период — это момент документа. Чистите его как подчинённый: по регистраторам.

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

Каскадное удаление и обработка ошибок

Каскад в 1С работает в двух местах. Удаление документа удаляет его движения во всех подчинённых регистрах. Удаление объекта удаляет строки регистров, где он стоит в ведущем измерении.

Чего каскад не делает:

  • 🚫 не трогает строки, где объект стоит в неведущем измерении или в ресурсе — они остаются с пустой ссылкой;
  • 🚫 не пересчитывает регистры с логической зависимостью;
  • 🚫 не срабатывает при пометке на удаление — только при окончательном удалении.

Подписки и обработчики

У набора записей могут быть обработчики ПередЗаписью в модуле набора и подписки на события. В типовых конфигурациях они проверяют данные, регистрируют изменения для обменов, пишут версии. При массовой очистке это лишняя работа и источник отказов.

Отключить бизнес-логику можно флагом:

Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать();

Флаг пропускает обработчики, но не права и не блокировки. Используйте его для служебной очистки, когда понимаете, что делают пропущенные обработчики.

Если база участвует в обмене (РИБ, обмен с другой программой), удаление попадёт в изменения и уйдёт на другие узлы. Чтобы этого не было, перед записью установите Набор.ОбменДанными.Получатели.АвтоЗаполнение = Ложь. Делайте так только при согласованной очистке на всех узлах.

Перехват ошибок

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

Пока Выборка.Следующий() Цикл
    Набор = РегистрыСведений.МойПодчиненныйРегистр.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
    Попытка
        Набор.Записать();
        Удалено = Удалено + 1;
    Исключение
        ЗаписьЖурналаРегистрации("Очистка регистра",
            УровеньЖурналаРегистрации.Ошибка, , Выборка.Регистратор,
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
КонецЦикла;

Частые тексты ошибок при очистке:

ОшибкаПричинаЧто делать
Нарушение прав доступа!У пользователя нет права изменять регистрЗапускайте от администратора или выдайте право на изменение регистра
Конфликт блокировок при выполнении транзакцииТе же строки сейчас пишет другой сеансПовторите позже или ночью, уменьшите порцию
Превышено максимальное время ожидания предоставления блокировкиДолгая транзакция держит записиДробите очистку на порции, не держите одну транзакцию на весь регистр

Большие объёмы: как очистить регистр без простоя

Регистр на несколько миллионов строк одним Набор.Записать() не чистят. Транзакция растёт, блокирует таблицу, на файловой базе может упасть по памяти. Пользователи в это время получают ошибки блокировок.

Что работает:

  1. Порции. Делите по периоду (месяц за месяцем) или по регистраторам. Каждый пустой набор с отбором — отдельная короткая транзакция.
  2. Ограничение выборки. В запросе используйте ВЫБРАТЬ ПЕРВЫЕ 10000 РАЗЛИЧНЫЕ ... и запускайте обработку повторно, пока выборка не станет пустой.
  3. Фоновое задание. Длинную очистку запускайте в фоновом задании. Сеанс клиента не повиснет, а прерванная очистка просто продолжится с оставшихся строк.
  4. Окно обслуживания. Массовое удаление запускайте ночью или в выходной, когда в базе мало пользователей.
  5. Обслуживание после. На SQL-сервере после массового удаления обновите статистику и перестройте индексы по плану обслуживания. В файловой базе размер файла 1Cv8.1CD сам не уменьшится — нужен режим «Тестирование и исправление» с флажком «Сжатие таблиц информационной базы».

«Тестирование и исправление» требует монопольного доступа: все пользователи должны выйти из базы. Предупредите их заранее, иначе их сеансы придётся завершать.

Прямое удаление строк из таблицы СУБД (DELETE, TRUNCATE в SQL) быстрее, но платформа об этом не узнает. Не обновятся служебные таблицы среза последних, если они включены у регистра. Не сработают обмены. Такой путь не поддерживается и оставляет базу в состоянии, которое потом сложно объяснить.

Перед массовой очисткой регистра
Выполнено: 0 / 6

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

Можно ли очистить подчинённый регистр без отбора по регистратору?
Нет. Для регистра, подчинённого регистратору, набор записей пишется только с отбором по регистратору. Чтобы очистить регистр целиком, перебирают всех регистраторов из запроса.
Почему после удаления справочника в регистре остались строки с пустой ссылкой?
Справочник стоял в неведущем измерении или в ресурсе. Каскад работает только для измерений со свойством «Ведущее». Такие строки удаляют обработкой по отбору на пустую ссылку.
Восстановятся ли записи подчинённого регистра при перепроведении документа?
Да, если движения формирует алгоритм проведения. Документ заново запишет свои строки по текущим данным. Исключение — документы с включённой ручной корректировкой движений.
Где посмотреть, кто удалил записи регистра?
В журнале регистрации: Администрирование → Обслуживание → «Журнал регистрации», отбор по событию изменения данных и по метаданным регистра. Запись есть, если уровень журнала не снижен до «Ошибки».
Уменьшится ли размер базы после очистки регистра?
В клиент-серверной базе место освободится внутри файлов СУБД, а сами файлы сжимают средствами СУБД. В файловой базе — только после сжатия таблиц в режиме «Тестирование и исправление».