Удаление записей подчинённого регистра сведений: вручную, кодом и порциями
Содержание
Зависимый регистр сведений
в 1С очищают через набор записей с отбором. Если регистр подчинён регистратору, ставят отбор по регистратору и записывают пустой набор Набор.Отбор.Регистратор.Установить(Документ) → Набор.Записать(). Если регистр независимый, но его измерение ссылается на справочник как ведущее, записи уйдут сами при удалении этого справочника. Вручную, в режиме Предприятия, получится удалить только записи независимого регистра: через Все функции → Регистры сведений.
Выбор способа зависит от того, от чего зависит регистр. От документа, от объекта в ведущем измерении или от логики другого регистра. Ошибка в выборе даёт два результата: проведённые документы без движений или «битые» ссылки <Объект не найден> в отчётах. Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конкретной конфигурации.
Какие регистры сведений считаются зависимыми
В метаданных у регистра сведений есть свойство «Режим записи». Вариантов два: «Независимый» и «Подчинение регистратору». От этого свойства и от свойств измерений зависит, кто управляет записями.
Под «зависимым» регистром на практике понимают один из трёх случаев:
- 📄 Подчинён регистратору. Записи — это движения документа. У каждой строки есть поле
Регистратор. Без документа записи не существуют. - 🔗 Есть ведущее измерение. Регистр независимый, но у измерения со ссылочным типом включено свойство «Ведущее». Записи живут, пока жив объект: удалили контрагента — удалились его строки.
- 🧮 Логическая зависимость. Регистр заполняется кодом конфигурации по данным другого регистра или документов. Платформа о связи не знает. Связь держится только на алгоритме.
Проверить вид регистра можно в Конфигураторе: откройте ветку Регистры сведений, двойной щелчок по регистру, вкладка «Основные» — там «Режим записи» и «Периодичность». Свойство «Ведущее» смотрите в палитре свойств каждого измерения.
Если доступа к Конфигуратору нет, подсказку даёт форма списка. У подчинённого регистра в списке есть колонка «Регистратор», а добавить запись кнопкой «Создать» нельзя.
Чем отличается очистка при разных типах зависимости
Тип зависимости определяет три вещи: какой отбор обязателен, что произойдёт с документами и справочниками, что увидят отчёты после удаления.
| Тип зависимости | Как удалить записи | Обязательный отбор | Риск |
|---|---|---|---|
| Подчинение регистратору | Отменить проведение документа или записать пустой набор по регистратору | Регистратор | Документ остаётся проведённым без движений |
| Ведущее измерение | Удалить объект или набор с отбором по измерению | Любые измерения, можно без отбора | Останутся строки с другими объектами в неведущих измерениях |
| Логическая зависимость | Набор записей + повторное заполнение алгоритмом конфигурации | Любой | Расхождение с исходным регистром |
У подчинённого регистра есть ещё одна связь — со свойством документа «Удаление движений». Его значения: «Удалять автоматически», «Удалять автоматически при отмене проведения», «Не удалять автоматически». При первых двух отмена проведения сама очищает записи регистра по этому документу.
Для регистра с ведущим измерением удаление объекта платформа обрабатывает каскадно. Пометка на удаление записи не трогает. Строки исчезают только при окончательном удалении объекта.
Очистка регистра сведений в режиме Предприятия
Без программирования доступно немногое. Но для разовой правки этого хватает.
Независимый регистр
- Включите команду «Все функции»:
Главное меню → Сервис → Параметры, флажок «Отображать команду “Все функции”». - Откройте
Главное меню → Все функции → Регистры сведенийи нужный регистр. - Сузьте список до нужных строк: отбор по периоду или измерению задаётся через меню
Ещёв командной панели списка. - Выделите строки (Shift или Ctrl + щелчок) и нажмите Delete. Подтвердите удаление.
Удаление записей регистра — окончательное. Пометки на удаление и корзины у регистров нет.
Перед удалением выгрузите базу в .dt или сделайте резервную копию SQL: восстановить строки регистра без копии нельзя.
Подчинённый регистр
Из формы списка подчинённого регистра строку не удалить: записи принадлежат документу. Варианты:
- ↩️ отменить проведение документа (команда в списке документов или в форме документа);
- ✏️ в типовых конфигурациях на базе БСП у многих документов есть флажок ручной корректировки движений — с ним строки правят прямо в документе;
- 🗑️ пометить документ на удаление и удалить через
Администрирование → Обслуживание→ «Удаление помеченных объектов».
Ручная корректировка снимает с документа автоматическое формирование движений. При следующем проведении программа не пересчитает записи сама. Снимите флажок, если хотите вернуть обычное поведение.
Регистр с ведущим измерением
Удалите объект, на который ссылается ведущее измерение. Сначала пометка на удаление, потом «Удаление помеченных объектов». Строки регистра с этим объектом удалятся вместе с ним.
Программная очистка: наборы записей и запросы
Основной инструмент — набор записей. Пустой набор, записанный с отбором, удаляет все строки под этот отбор. Код запускают на сервере: из внешней обработки (.epf) в процедуре с директивой &НаСервере.
Полная очистка независимого регистра
&НаСервере
Процедура ОчиститьРегистрПолностьюНаСервере()
Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
// Отбор не устанавливаем: пустой набор без отбора удаляет все записи
Набор.Записать();
КонецПроцедуры
Для регистра на десятки тысяч строк это нормально. Для миллионов — нет: всё уйдёт одной транзакцией. Как дробить, ниже.
Удаление по измерению
Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Контрагент.Установить(СсылкаНаКонтрагента);
Набор.Записать();
Отбор ставится только на равенство. Условия «больше», «меньше», «в списке» набор не принимает. Для них сначала делают запрос, потом удаляют по каждому найденному значению.
Одна запись через менеджер записи
Менеджер = РегистрыСведений.МойРегистр.СоздатьМенеджерЗаписи();
Менеджер.Период = ДатаЗаписи;
Менеджер.Контрагент = СсылкаНаКонтрагента;
Менеджер.Прочитать();
Если Менеджер.Выбран() Тогда
Менеджер.Удалить();
КонецЕсли;
Менеджер записи есть только у независимых регистров. У подчинённого его нет.
Подчинённый регистр: удаление по регистраторам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Т.Регистратор КАК Регистратор
|ИЗ
| РегистрСведений.МойПодчиненныйРегистр КАК Т
|ГДЕ
| Т.Период МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Начало", НачалоПериода);
Запрос.УстановитьПараметр("Конец", КонецПериода);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Набор = РегистрыСведений.МойПодчиненныйРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
Набор.Записать();
КонецЦикла;
Если нужно убрать только часть строк документа, прочитайте набор, удалите лишние строки и запишите обратно. Удаляйте с конца, чтобы не сбить индексы:
Набор.Отбор.Регистратор.Установить(Документ);
Набор.Прочитать();
Для Сч = 1 По Набор.Количество() Цикл
Запись = Набор[Набор.Количество() - Сч];
Если Запись.Контрагент = ЛишнийКонтрагент Тогда
Набор.Удалить(Запись);
КонецЕсли;
КонецЦикла;
Набор.Записать();
После такой очистки документ остаётся проведённым. Отчёты по регистру покажут пустоту, а сам документ — галочку «Проведён». При перепроведении движения вернутся. Если цель — убрать данные насовсем, удаляйте или распроводите сами документы.
Периодический регистр: удаление старой истории
Периодические регистры (курсы, цены, настройки по датам) чаще всего чистят от старой истории. Здесь есть ловушка: срез последних.
Пример. Цена товара записана 15.03 — 100 руб., 01.07 — 120 руб. Нужно удалить всё до 01.06. Если удалить запись от 15.03, то на 10.06 цена станет пустой. Хотя на эту дату действовала цена 100 руб.
Правильный порядок:
- Определите дату отсечения, например 01.06.
- Для каждой комбинации измерений запросом найдите последнюю запись до даты отсечения.
- Перенесите её значение на дату отсечения (запишите новую строку с периодом 01.06), если на эту дату записи ещё нет.
- Удалите все записи с периодом меньше даты отсечения.
Удаление по периоду для независимого регистра:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Т.Период КАК Период
|ИЗ
| РегистрСведений.МойПериодическийРегистр КАК Т
|ГДЕ
| Т.Период < &ДатаОтсечения";
Запрос.УстановитьПараметр("ДатаОтсечения", ДатаОтсечения);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Набор = РегистрыСведений.МойПериодическийРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(Выборка.Период);
Набор.Записать();
КонецЦикла;
Отбор только по периоду удаляет все строки этой даты по всем измерениям. Если нужно оставить часть измерений, добавьте отбор по ним или выбирайте в запросе пары «период + измерение».
Для регистра с периодичностью «По позиции регистратора» период — это момент документа. Чистите его как подчинённый: по регистраторам.
Перенос значения на дату отсечения нужен не всегда. Для журналов (лог событий, история статусов) старые строки просто удаляют. Для справочных данных (цены, курсы, ставки) — переносят, иначе отчёты за новый период покажут пустые значения.
Каскадное удаление и обработка ошибок
Каскад в 1С работает в двух местах. Удаление документа удаляет его движения во всех подчинённых регистрах. Удаление объекта удаляет строки регистров, где он стоит в ведущем измерении.
Чего каскад не делает:
- 🚫 не трогает строки, где объект стоит в неведущем измерении или в ресурсе — они остаются с пустой ссылкой;
- 🚫 не пересчитывает регистры с логической зависимостью;
- 🚫 не срабатывает при пометке на удаление — только при окончательном удалении.
Подписки и обработчики
У набора записей могут быть обработчики ПередЗаписью в модуле набора и подписки на события. В типовых конфигурациях они проверяют данные, регистрируют изменения для обменов, пишут версии. При массовой очистке это лишняя работа и источник отказов.
Отключить бизнес-логику можно флагом:
Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать();
Флаг пропускает обработчики, но не права и не блокировки. Используйте его для служебной очистки, когда понимаете, что делают пропущенные обработчики.
Если база участвует в обмене (РИБ, обмен с другой программой), удаление попадёт в изменения и уйдёт на другие узлы. Чтобы этого не было, перед записью установите Набор.ОбменДанными.Получатели.АвтоЗаполнение = Ложь. Делайте так только при согласованной очистке на всех узлах.
Перехват ошибок
Одна сбойная запись не должна обрывать всю очистку. Оборачивайте запись набора в попытку и пишите ошибку в журнал регистрации:
Пока Выборка.Следующий() Цикл
Набор = РегистрыСведений.МойПодчиненныйРегистр.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
Попытка
Набор.Записать();
Удалено = Удалено + 1;
Исключение
ЗаписьЖурналаРегистрации("Очистка регистра",
УровеньЖурналаРегистрации.Ошибка, , Выборка.Регистратор,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
Частые тексты ошибок при очистке:
| Ошибка | Причина | Что делать |
|---|---|---|
Нарушение прав доступа! | У пользователя нет права изменять регистр | Запускайте от администратора или выдайте право на изменение регистра |
Конфликт блокировок при выполнении транзакции | Те же строки сейчас пишет другой сеанс | Повторите позже или ночью, уменьшите порцию |
Превышено максимальное время ожидания предоставления блокировки | Долгая транзакция держит записи | Дробите очистку на порции, не держите одну транзакцию на весь регистр |
Большие объёмы: как очистить регистр без простоя
Регистр на несколько миллионов строк одним Набор.Записать() не чистят. Транзакция растёт, блокирует таблицу, на файловой базе может упасть по памяти. Пользователи в это время получают ошибки блокировок.
Что работает:
- Порции. Делите по периоду (месяц за месяцем) или по регистраторам. Каждый пустой набор с отбором — отдельная короткая транзакция.
- Ограничение выборки. В запросе используйте
ВЫБРАТЬ ПЕРВЫЕ 10000 РАЗЛИЧНЫЕ ...и запускайте обработку повторно, пока выборка не станет пустой. - Фоновое задание. Длинную очистку запускайте в фоновом задании. Сеанс клиента не повиснет, а прерванная очистка просто продолжится с оставшихся строк.
- Окно обслуживания. Массовое удаление запускайте ночью или в выходной, когда в базе мало пользователей.
- Обслуживание после. На SQL-сервере после массового удаления обновите статистику и перестройте индексы по плану обслуживания. В файловой базе размер файла
1Cv8.1CDсам не уменьшится — нужен режим «Тестирование и исправление» с флажком «Сжатие таблиц информационной базы».
«Тестирование и исправление» требует монопольного доступа: все пользователи должны выйти из базы. Предупредите их заранее, иначе их сеансы придётся завершать.
Прямое удаление строк из таблицы СУБД (DELETE, TRUNCATE в SQL) быстрее, но платформа об этом не узнает. Не обновятся служебные таблицы среза последних, если они включены у регистра. Не сработают обмены. Такой путь не поддерживается и оставляет базу в состоянии, которое потом сложно объяснить.
Частые вопросы
Можно ли очистить подчинённый регистр без отбора по регистратору?
Почему после удаления справочника в регистре остались строки с пустой ссылкой?
Восстановятся ли записи подчинённого регистра при перепроведении документа?
Где посмотреть, кто удалил записи регистра?
Администрирование → Обслуживание → «Журнал регистрации», отбор по событию изменения данных и по метаданным регистра. Запись есть, если уровень журнала не снижен до «Ошибки».