Как очистить регистр сведений 1С с отбором по ресурсу

Программист 1С v8.3 (Обычные формы) Налоговый учет
← На главную

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

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

Почему нельзя использовать стандартный отбор по ресурсу?

Для начала проанализируем архитектуру регистров сведений. Платформа 1С проектировалась таким образом, что поиск и фильтрация в объекте НаборЗаписей осуществляются только по ключевым полям, которые образуют уникальный ключ записи. К таким полям относятся:

  1. Период (для периодических регистров).
  2. Регистратор (для регистров, подчиненных регистратору).
  3. Измерения (для всех типов регистров).

Ресурсы и реквизиты не входят в этот список, поэтому при попытке обратиться к ним через НаборЗаписей.Отбор.Организация (если Организация — это ресурс), система выдаст ошибку "Поле объекта не обнаружено". Для решения этой проблемы нам придется использовать обходные пути.

Способ 1. Удаление через Менеджер записи в цикле

Это самый простой в реализации метод. Основная идея заключается в том, чтобы сначала запросом выбрать все комбинации ключевых полей (период и измерения), которые соответствуют нашему условию по ресурсу, а затем в цикле удалить их по одной.

Рассмотрим подробнее программный код этого метода:


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

Запрос.УстановитьПараметр("Организация", ВыбраннаяОрганизация);
Выборка = Запрос.Выполнить().Выбрать();

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

Важное замечание: Этот метод хорошо подходит для небольших объемов данных. Однако, если в регистре десятки тысяч записей, он будет работать медленно, так как на каждое удаление инициируется отдельное обращение к базе данных и фиксация транзакции.

Способ 2. Оптимизированное удаление через Набор записей

Для ускорения процесса мы можем использовать НаборЗаписей. В отличие от менеджера записи, набор позволяет работать с группой данных. Разберем ситуацию: если мы установим отбор по ФизЛицу и Периоду, а затем запишем пустой набор, это будет работать быстрее.

Проанализируем шаги реализации:

  1. Выбираем запросом уникальные ключи записей.
  2. Для каждой уникальной комбинации создаем НаборЗаписей.
  3. Устанавливаем Отбор по всем измерениям.
  4. Вызываем метод Записать() без добавления новых строк в набор.

НаборЗаписей = РегистрыСведений.НДФЛПрименениеВычетов.СоздатьНаборЗаписей();

// Выборка ключей записей
Запрос = Новый Запрос("ВЫБРАТЬ Период, ФизЛицо ИЗ РегистрСведений.НДФЛПрименениеВычетов ГДЕ Организация = &Орг");
Запрос.УстановитьПараметр("Орг", НужнаяОрганизация);
Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл
    НаборЗаписей.Отбор.Период.Установить(Результат.Период);
    НаборЗаписей.Отбор.ФизЛицо.Установить(Результат.ФизЛицо);
    
    // Записываем пустой набор, что фактически удаляет запись из базы
    НаборЗаписей.Записать();
КонецЦикла;

Способ 3. Метод «Полной перезаписи» (для массового удаления)

Если вам нужно удалить значительную часть регистра (более 50-70% записей), выполнение тысяч точечных удалений может привести к сильной фрагментации индексов в базе данных SQL. В таких случаях эффективнее использовать метод «переливки» данных. Если же перед вами стоит задача полностью очистить базу от сведений по конкретному юрлицу, то для этого выполняют выборочное удаление организации из 1С с автоматической очисткой связанных документов и регистров.

Выясним пошагово, как это сделать:

  1. Выгружаем в Таблицу Значений все записи регистра, которые НЕ соответствуют условию удаления (то есть те, которые мы хотим оставить).
  2. Очищаем регистр полностью.
  3. Загружаем данные из таблицы значений обратно.

// 1. Выбираем данные, которые должны ОСТАТЬСЯ
Запрос = Новый Запрос(
    "ВЫБРАТЬ * ИЗ РегистрСведений.НДФЛПрименениеВычетов ГДЕ Организация <> &ОрганизацияДляУдаления"
);
Запрос.УстановитьПараметр("ОрганизацияДляУдаления", УдаляемаяОрг);
ТаблицаОстающихсяДанных = Запрос.Выполнить().Выгрузить();

// 2. Полная очистка регистра (ВНИМАНИЕ: удаляет ВСЕ записи)
Набор = РегистрыСведений.НДФЛПрименениеВычетов.СоздатьНаборЗаписей();
// Запись пустого набора без установленных отборов очищает весь регистр
Набор.Записать(Истина); 

// 3. Загрузка данных обратно
// Используем ОбменДанными.Загрузка для ускорения и обхода проверок
Набор.ОбменДанными.Загрузка = Истина;
Набор.Загрузить(ТаблицаОстающихсяДанных);
Набор.Записать();

Внимание! Этот метод требует осторожности. Если в момент между очисткой и загрузкой произойдет критическая ошибка (например, отключение питания сервера), данные могут быть потеряны. Всегда делайте резервную копию перед такими операциями. Для создания резервных копий перед любыми критическими изменениями в базах можно настроить автоматическое архивирование баз 1С в фоновом режиме.

Рекомендации по оптимизации и безопасности

Для того чтобы процесс чистки прошел максимально гладко и быстро, рекомендуем придерживаться следующих правил:

1. Использование транзакций. Если вы используете удаление в цикле (Способ 1 или 2), обязательно оберните цикл в транзакцию. Это позволит базе данных зафиксировать все изменения одним пакетом, что ускорит работу в десятки раз.


НачатьТранзакцию();
Попытка
    // Ваш цикл удаления здесь
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;

2. Свойство ОбменДанными.Загрузка. Перед вызовом метода Записать() всегда устанавливайте НаборЗаписей.ОбменДанными.Загрузка = Истина. Это отключает обработчики событий (ПередЗаписью, ПриЗаписи), которые могут содержать тяжелые проверки или логику, замедляющую процесс.

3. Порционное удаление. При работе с миллионами записей в SQL-базе массовое удаление может вызвать блокировку всей таблицы, что парализует работу других пользователей. В таких случаях разделите удаление на порции (например, по 1000 записей) и фиксируйте транзакцию после каждой порции.

4. Нюансы периодичности. Помните, что в периодическом регистре ключ записи — это Период + Измерения. Если вы забудете установить отбор по Период в НабореЗаписей, система удалит все записи по данному физлицу за все даты. Всегда проверяйте состав ключевых полей в конфигураторе. Для анализа и удаления записей за интервал дат подойдёт обработка для очистки регистров сведений и накопления по выбранному периоду.

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

← На главную