При работе с платформой 1С:Предприятие программисты часто сталкиваются с задачей очистки или корректировки записей в регистрах сведений. Если регистр независимый и нам нужно удалить данные по определенным значениям измерений, задача решается стандартным методом Установить в объекте Отбор. Однако ситуация значительно усложняется, когда критерий удаления — это значение ресурса или реквизита регистра.
В этой статье мы подробно разберем, почему стандартный отбор не работает для ресурсов, и рассмотрим эффективные программные способы решения этой задачи на примере регистра НДФЛПрименениеВычетов из конфигурации УПП.
Для начала проанализируем архитектуру регистров сведений. Платформа 1С проектировалась таким образом, что поиск и фильтрация в объекте НаборЗаписей осуществляются только по ключевым полям, которые образуют уникальный ключ записи. К таким полям относятся:
Ресурсы и реквизиты не входят в этот список, поэтому при попытке обратиться к ним через НаборЗаписей.Отбор.Организация (если Организация — это ресурс), система выдаст ошибку "Поле объекта не обнаружено". Для решения этой проблемы нам придется использовать обходные пути.
Это самый простой в реализации метод. Основная идея заключается в том, чтобы сначала запросом выбрать все комбинации ключевых полей (период и измерения), которые соответствуют нашему условию по ресурсу, а затем в цикле удалить их по одной.
Рассмотрим подробнее программный код этого метода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НДФЛ.Период,
| НДФЛ.ФизЛицо
|ИЗ
| РегистрСведений.НДФЛПрименениеВычетов КАК НДФЛ
|ГДЕ
| НДФЛ.Организация = &Организация";
Запрос.УстановитьПараметр("Организация", ВыбраннаяОрганизация);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
МЗ = РегистрыСведений.НДФЛПрименениеВычетов.СоздатьМенеджерЗаписи();
// Заполняем ключевые поля для однозначной идентификации записи
МЗ.Период = Выборка.Период;
МЗ.ФизЛицо = Выборка.ФизЛицо;
// Просим систему прочитать запись и удалить ее
МЗ.Удалить();
КонецЦикла;
Важное замечание: Этот метод хорошо подходит для небольших объемов данных. Однако, если в регистре десятки тысяч записей, он будет работать медленно, так как на каждое удаление инициируется отдельное обращение к базе данных и фиксация транзакции.
Для ускорения процесса мы можем использовать НаборЗаписей. В отличие от менеджера записи, набор позволяет работать с группой данных. Разберем ситуацию: если мы установим отбор по ФизЛицу и Периоду, а затем запишем пустой набор, это будет работать быстрее.
Проанализируем шаги реализации:
НаборЗаписей.Отбор по всем измерениям.Записать() без добавления новых строк в набор.
НаборЗаписей = РегистрыСведений.НДФЛПрименениеВычетов.СоздатьНаборЗаписей();
// Выборка ключей записей
Запрос = Новый Запрос("ВЫБРАТЬ Период, ФизЛицо ИЗ РегистрСведений.НДФЛПрименениеВычетов ГДЕ Организация = &Орг");
Запрос.УстановитьПараметр("Орг", НужнаяОрганизация);
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
НаборЗаписей.Отбор.Период.Установить(Результат.Период);
НаборЗаписей.Отбор.ФизЛицо.Установить(Результат.ФизЛицо);
// Записываем пустой набор, что фактически удаляет запись из базы
НаборЗаписей.Записать();
КонецЦикла;
Если вам нужно удалить значительную часть регистра (более 50-70% записей), выполнение тысяч точечных удалений может привести к сильной фрагментации индексов в базе данных SQL. В таких случаях эффективнее использовать метод «переливки» данных. Если же перед вами стоит задача полностью очистить базу от сведений по конкретному юрлицу, то для этого выполняют выборочное удаление организации из 1С с автоматической очисткой связанных документов и регистров.
Выясним пошагово, как это сделать:
// 1. Выбираем данные, которые должны ОСТАТЬСЯ
Запрос = Новый Запрос(
"ВЫБРАТЬ * ИЗ РегистрСведений.НДФЛПрименениеВычетов ГДЕ Организация <> &ОрганизацияДляУдаления"
);
Запрос.УстановитьПараметр("ОрганизацияДляУдаления", УдаляемаяОрг);
ТаблицаОстающихсяДанных = Запрос.Выполнить().Выгрузить();
// 2. Полная очистка регистра (ВНИМАНИЕ: удаляет ВСЕ записи)
Набор = РегистрыСведений.НДФЛПрименениеВычетов.СоздатьНаборЗаписей();
// Запись пустого набора без установленных отборов очищает весь регистр
Набор.Записать(Истина);
// 3. Загрузка данных обратно
// Используем ОбменДанными.Загрузка для ускорения и обхода проверок
Набор.ОбменДанными.Загрузка = Истина;
Набор.Загрузить(ТаблицаОстающихсяДанных);
Набор.Записать();
Внимание! Этот метод требует осторожности. Если в момент между очисткой и загрузкой произойдет критическая ошибка (например, отключение питания сервера), данные могут быть потеряны. Всегда делайте резервную копию перед такими операциями. Для создания резервных копий перед любыми критическими изменениями в базах можно настроить автоматическое архивирование баз 1С в фоновом режиме.
Для того чтобы процесс чистки прошел максимально гладко и быстро, рекомендуем придерживаться следующих правил:
1. Использование транзакций. Если вы используете удаление в цикле (Способ 1 или 2), обязательно оберните цикл в транзакцию. Это позволит базе данных зафиксировать все изменения одним пакетом, что ускорит работу в десятки раз.
НачатьТранзакцию();
Попытка
// Ваш цикл удаления здесь
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
2. Свойство ОбменДанными.Загрузка. Перед вызовом метода Записать() всегда устанавливайте НаборЗаписей.ОбменДанными.Загрузка = Истина. Это отключает обработчики событий (ПередЗаписью, ПриЗаписи), которые могут содержать тяжелые проверки или логику, замедляющую процесс.
3. Порционное удаление. При работе с миллионами записей в SQL-базе массовое удаление может вызвать блокировку всей таблицы, что парализует работу других пользователей. В таких случаях разделите удаление на порции (например, по 1000 записей) и фиксируйте транзакцию после каждой порции.
4. Нюансы периодичности. Помните, что в периодическом регистре ключ записи — это Период + Измерения. Если вы забудете установить отбор по Период в НабореЗаписей, система удалит все записи по данному физлицу за все даты. Всегда проверяйте состав ключевых полей в конфигураторе. Для анализа и удаления записей за интервал дат подойдёт обработка для очистки регистров сведений и накопления по выбранному периоду.
Подведем итог: несмотря на отсутствие прямого отбора по ресурсу, задача легко решается предварительной выборкой ключей через запрос. Выбор конкретного метода зависит от объема данных и критичности времени выполнения операции. Для комплексной очистки движений в разрезе конкретной организации можно использовать обработку для выборочного удаления данных по организациям.