Как правильно удалить документы с движениями из базы 1С средствами SQL Server

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Иногда возникают ситуации, когда стандартное удаление объектов через интерфейс 1С или программный метод Удалить() не подходит. Чаще всего это связано с экстремально большими объемами данных, например, при свертке базы за много лет или при необходимости полной очистки данных по одной организации в огромной базе. В подобных сценариях часто применяется универсальная очистка базы и удаление документов по организации. В таких случаях программисты прибегают к «хирургическому» вмешательству — удалению данных напрямую средствами SQL. Разберем подробно, как реализовать этот процесс, не превратив базу в набор «битых» ссылок.

Определяем структуру хранения данных

Прежде чем приступать к удалению, нам необходимо выяснить, в каких именно таблицах SQL Server лежат данные нужных нам документов. В 1С имена таблиц в СУБД (например, _Document150) не совпадают с именами объектов в конфигураторе. Проанализируем, как получить эти соответствия и выполнить сопоставление объектов метаданных 1С и таблиц SQL Server. Мы не будем гадать или искать таблицы вручную — для этого в платформе 1С предусмотрен штатный механизм. Чтобы упростить эту задачу, можно использовать готовую обработку, описывающую структуру хранения базы данных.

Воспользуемся методом ПолучитьСтруктуруХраненияБазыДанных(). Этот метод возвращает таблицу значений, в которой указаны имена таблиц SQL для самого документа, его табличных частей, движений по регистрам и даже таблиц регистрации изменений для планов обмена. Рассмотрим пример кода, который поможет нам собрать информацию о «целях» для удаления:


ИменаМетаданных = Новый Массив;
ИменаМетаданных.Добавить("Документ.РеализацияТоваровУслуг");
Структура = ПолучитьСтруктуруХраненияБазыДанных(ИменаМетаданных, Истина);

Для Каждого СтрокаСтруктуры Из Структура Цикл
    // Здесь мы получаем ИмяТаблицыХранения (SQL-имя) 
    // и Назначение (Основная, ТабличнаяЧасть, Движения и т.д.)
    Сообщить("Объект: " + СтрокаСтруктуры.ИмяТаблицы + " -> SQL: " + СтрокаСтруктуры.ИмяТаблицыХранения);
КонецЦикла;

Работа с уникальными идентификаторами (GUID)

Одной из главных сложностей при работе с SQL напрямую является формат хранения ссылок. В 1С идентификатор binary(16) хранится в специфическом виде. Если мы просто возьмем UUID из 1С, он не совпадет с тем, что мы увидим в колонке _IDRRef в SQL без преобразования, учитывающего все особенности работы с уникальными идентификаторами (GUID) в прямых SQL-запросах. Понимание этих нюансов необходимо, когда мы анализируем SQL сервер глазами 1С-ника для поиска проблемных записей.

Разберем ситуацию: для удаления строк из табличных частей (например, _Document150_VT152), нам нужно знать _DocumentIDRRef, который соответствует _IDRRef из основной таблицы документа. Выясним, как преобразовать ссылку 1С в HEX-строку, которую поймет SQL Server. Посмотрим на пример функции для формирования бинарного представления:


// Пример преобразования идентификатора для использования в SQL запросе
Функция ПолучитьHexСсылку(Ссылка)
    Идентификатор = Ссылка.УникальныйИдентификатор();
    Стр = СтрЗаменить(Строка(Идентификатор), "-", "");
    // В SQL 1С байты GUID перевернуты особым образом
    // Для простоты формирования запроса через ADO можно использовать HEX-константу
    Возврат "0x" + Сред(Стр, 25, 8) + Сред(Стр, 21, 4) + Сред(Стр, 17, 4) + Сред(Стр, 1, 16);
КонецФункции

Важный момент: Современные версии SQL Server позволяют передавать параметры в запросы напрямую через ADO в бинарном виде, что избавляет от необходимости вручную переворачивать байты. Однако понимание структуры HEX-строки критично при отладке запросов в SQL Management Studio.

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

Проанализируем правильную последовательность действий. Нельзя просто удалить запись из таблицы документа. Если мы удалим «шапку», а выполнение скрипта прервется, в базе останутся «сироты» в табличных частях и движениях, которые потом будет крайне сложно найти и вычистить. Рассмотрим правильный алгоритм действий, направленный на обеспечение ссылочной целостности при прямом удалении данных из 1С:

  1. Регистрация изменений: Очищаем таблицу планов обмена (обычно это таблицы с суффиксом _ChngR). Если этого не сделать, механизмы синхронизации будут пытаться отправить в другие базы данные об объекте, которого уже нет.
  2. Табличные части: Удаляем записи из всех подчиненных таблиц вида _DocumentN_VT_M, где _DocumentIDRRef совпадает с идентификатором документа.
  3. Движения регистров: Очищаем таблицы регистров накопления, бухгалтерии и сведений, где данный документ выступает регистратором. Для точечной работы с этим этапом можно использовать специализированное удаление движений документов по фильтрам.
  4. Основная таблица: В последнюю очередь удаляем запись из таблицы _DocumentN.

Использование SQL-транзакций

Чтобы гарантировать целостность данных, все операции удаления должны выполняться внутри блока BEGIN TRANSACTION. Это обеспечит принцип «все или ничего»: если при удалении хотя бы одной строки возникнет ошибка (например, из-за блокировки), SQL Server откатит все изменения назад к исходному состоянию.

Рассмотрим структуру SQL-скрипта, который мы можем сформировать в 1С и отправить на исполнение через ADODB.Connection:


BEGIN TRANSACTION;
BEGIN TRY
    -- Удаляем движения по регистру накопления
    DELETE FROM _AccumReg120 WHERE _RecorderRRef = @DocRef;
    
    -- Удаляем табличные части
    DELETE FROM _Document150_VT152 WHERE _DocumentIDRRef = @DocRef;
    
    -- Удаляем сам документ
    DELETE FROM _Document150 WHERE _IDRRef = @DocRef;

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    -- Здесь можно получить описание ошибки через ERROR_MESSAGE()
END CATCH;

Проблема итогов и составных типов данных

Самая большая «подводная камнь» при удалении через SQL — это итоги регистров. В 1С таблицы итогов (_AccumRegTotals) хранят рассчитанные остатки на начало каждого месяца. При прямом удалении движений из основной таблицы регистра SQL Server не пересчитывает итоги автоматически, так как логика расчета находится на стороне сервера приложений 1С.

Выясним, что нужно сделать после завершения SQL-операций. Обязательно необходимо выполнить пересчет итогов в 1С:Предприятие после манипуляций на уровне SQL. Это можно сделать через Конфигуратор или программно. Без этой процедуры отчеты будут показывать старые остатки, несмотря на отсутствие записей в базе.

Также проанализируем ситуацию с составными типами данных. Если ссылка на удаляемый документ хранится в реквизите другого объекта, то после удаления эти поля в других таблицах станут указывать на несуществующий объект. Это приведет к появлению надписей «Объект не найден». В таких ситуациях крайне полезным оказывается универсальное удаление движений по битым ссылкам, которое позволяет вычистить проблемные записи без долгого тестирования и исправления всей базы.

Оптимизация: транзакционный лог и кэш

При массовом удалении (миллионы строк) файл лога транзакций (.ldf) может вырасти до гигантских размеров. Разберем, как этого избежать, выполнив грамотную настройку лога транзакций и модели восстановления при массовых операциях:

Подведем итог: удаление через SQL — это мощный инструмент, который требует от программиста четкого понимания структуры базы данных _IDRRef, _TRef и связей между таблицами. Используйте этот метод только тогда, когда стандартные средства 1С не справляются с объемом задачи, и всегда делайте резервную копию базы перед началом работ.

← На главную