В процессе работы с базами данных 1С нередко возникают ситуации, когда требуется массово пометить на удаление тысячи документов. Это может быть результатом некорректной работы сторонней обработки, миграции данных или просто технической необходимостью. Однако стандартная «Групповая обработка состава документов» или встроенное «Групповое изменение реквизитов» при определенных настройках могут оставить за собой «шлейф» из записей в регистрах накопления, бухгалтерии или сведений. В результате документ помечен на удаление, но его движения продолжают влиять на остатки и отчеты.
В этой статье мы подробно разберем, почему так происходит, проанализируем типичные ошибки и рассмотрим правильные программные способы решения задачи.
Рассмотрим ситуацию, описанную в теме: пользователь пытается пометить документы, включив режим ОбменДанными.Загрузка = Истина. Это распространенная ошибка при попытке ускорить процесс. Разберем по шагам, что происходит в системе в этот момент:
ПередЗаписью, ПриЗаписи).Истина в реквизит ПометкаУдаления и устанавливает состояние Проведен = Ложь в заголовке таблицы документа, но не заходит в логику удаления движений.В итоге мы получаем «битые» ссылки в регистрах: записи в таблицах движений ссылаются на регистратор, который уже считается неактивным, но сами записи физически существуют и учитываются в итогах. Проанализируем, как этого избежать. Для обнаружения и исправления таких ситуаций подойдет инструмент для поиска и исправления документов с ошибками проведения.
Самый правильный и надежный способ для объема в несколько тысяч документов (например, 7 500 штук) — написать простую внешнюю обработку. Вместо прямого изменения реквизита мы будем использовать специализированный метод УстановитьПометкуУдаления(). Он гарантирует, что система отработает штатно: снимет с проведения и очистит регистры.
Рассмотрим пример кода для такой обработки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПриходТовара.Ссылка КАК Ссылка
|ИЗ
| Документ.ПриходТовара КАК ПриходТовара
|ГДЕ
| НЕ ПриходТовара.ПометкаУдаления
| И ПриходТовара.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания";
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДата()));
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем объект документа для изменения
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Метод УстановитьПометкуУдаления(Истина) делает все необходимые действия:
// 1. Снимает с проведения (если был проведен)
// 2. Очищает движения во всех регистрах
// 3. Устанавливает флаг пометки удаления
ДокОбъект.УстановитьПометкуУдаления(Истина);
КонецЦикла;
Этот метод работает медленнее, чем прямая запись, так как требует получения объекта и выполнения его внутренней логики, но он абсолютно безопасен для целостности данных.
Если вы уже успели пометить документы на удаление «быстрым» способом (через групповое изменение реквизитов с флагом загрузки) и теперь видите движения в отчетах, нам нужно принудительно очистить наборы записей. Выясним, как это сделать программно, не снимая пометку удаления. Для этой задачи можно использовать обработку для очистки движений документов по фильтрам.
Для каждого типа регистра, в котором остались записи, необходимо выполнить следующий алгоритм:
// Предположим, мы чистим регистр накопления "ТоварыНаСкладах"
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ТоварыНаСкладах.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
|ГДЕ
| ТоварыНаСкладах.Регистратор.ПометкаУдаления";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Создаем пустой набор записей с отбором по конкретному документу
Набор = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
// Записываем пустой набор, тем самым удаляя старые записи из БД
Набор.Записать(Истина);
КонецЦикла;
Важный нюанс: метод Записать(Истина) с пустым набором эффективно удаляет все записи регистра по данному регистратору. Это значительно быстрее, чем перепроведение документов.
В современных конфигурациях (ЕРП, УТ 11, Бухгалтерия 3.0) разработчики 1С уже предусмотрели инструменты для массовой работы с объектами. Если мы хотим сделать все максимально эффективно, стоит обратиться к общему модулю ОбменДаннымиСервер.
Проанализируем метод УдалитьДвиженияДокумента(). Он позволяет очистить все движения документа по всем регистрам одной командой, не заботясь о перечислении конкретных имен регистров. Это удобно, если документ делает записи в десятки разных таблиц.
// Пример использования БСП для очистки движений
Для Каждого ДокСсылка Из МассивДокументов Цикл
ОбменДаннымиСервер.УдалитьДвиженияДокумента(ДокСсылка);
КонецЦикла;
Когда количество документов исчисляется не тысячами, а миллионами, объектная модель 1С может работать слишком долго. В этом случае системные администраторы и ведущие разработчики используют прямые SQL-запросы к таблицам базы данных. Рассмотрим этот процесс теоретически, так как он требует крайней осторожности:
_DocumentXXX) и таблицы движений (_AccumRegXXX).UPDATE для таблицы документов, устанавливающий флаг пометки удаления и снимающий флаг проведения.DELETE записей в таблицах движений, где идентификатор регистратора совпадает со списком удаляемых документов.Если 7 500 документов все же обрабатываются слишком долго (например, из-за сложных подписок на события), проанализируем следующие советы:
Подводя итог, можно сказать, что для большинства задач лучшим выбором будет Способ 1 с использованием УстановитьПометкуУдаления(Истина) без использования флага Загрузка = Истина. Это гарантирует чистоту информационной базы и отсутствие «фантомных» остатков в регистрах.