Как составить прямой запрос в 1С++ для удаления записей из регистров по помеченной на удаление номенклатуре?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

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

Разберем по шагам, как устроено хранение регистров в 1С 7.7, как предварительно протестировать выборку и как корректно выполнить удаление записей.

Структура таблиц регистров и метапарсер 1С++

В архитектуре 1С 7.7 каждый регистр остатков физически делится на две независимые таблицы на уровне Microsoft SQL Server:

  1. Таблица движений (в СУБД имеет префикс RAxxxx, где xxxx — идентификатор регистра). Содержит каждую отдельную запись, порожденную проведением документов: позицию документа, знак движения (+/-) и значения измерений и ресурсов. В метапарсере 1С++ к ней обращаются через конструкцию $Регистр.ИмяРегистра.
  2. Таблица итогов (в СУБД имеет префикс RGxxxx). Содержит рассчитанные срезы остатков на начало каждого расчетного периода (месяца), зафиксированные в поле PERIOD. В метапарсере 1С++ к этой таблице обращаются как $РегистрИтоги.ИмяРегистра.

Справочник номенклатуры хранится в таблице с префиксом SCxxxx (метаимя $Справочник.Номенклатура), а признак пометки на удаление определяется полем ISMARK (где значение 1 означает установленную пометку).

Тестирование выборки данных перед удалением

Любые деструктивные операции с базой данных категорически не рекомендуется выполнять без предварительной проверки. Сначала сформируем и выполним проверочный SELECT, чтобы увидеть, какие именно строки попадают под условие.

Посмотрим на пример запроса через метапарсер 1С++, связывающий таблицу движений регистра «ОстаткиТМЦ» со справочником «Номенклатура»:


SELECT TOP 100 
    Номенклатура.descr [Наименование $Справочник.Номенклатура],
    ОстаткиТМЦ.$ОстаткиТМЦ.Номенклатура [Номенклатура $Справочник.Номенклатура]
FROM $Регистр.ОстаткиТМЦ AS ОстаткиТМЦ
INNER JOIN $Справочник.Номенклатура AS Номенклатура 
    ON ОстаткиТМЦ.$ОстаткиТМЦ.Номенклатура = Номенклатура.ID
WHERE Номенклатура.ISMARK = 1

Если запрос тестируется напрямую в SQL Server Management Studio (или Query Analyzer) без метапарсера 1С++, используются физические имена таблиц и полей из словаря данных (файла 1cv7.dd):


SELECT TOP 100 
    Номенклатура.descr, 
    ОстаткиТМЦ.SP2343 
FROM RG2351 AS ОстаткиТМЦ 
INNER JOIN SC84 AS Номенклатура 
    ON ОстаткиТМЦ.SP2343 = Номенклатура.ID 
WHERE Номенклатура.ISMARK = 1

Здесь RG2351 — таблица итогов регистра, SP2343 — колонка измерения «Номенклатура», а SC84 — физическая таблица справочника номенклатуры.

Варианты запросов на удаление записей (DELETE)

Когда мы убедились, что в выборку попадают только нужные строки, перейдем к конструкции удаления. В T-SQL существует два основных способа написания такой команды.

Вариант 1: Удаление с объединением таблиц (INNER JOIN)

В T-SQL при использовании JOIN в инструкции DELETE обязательно указывается алиас целевой таблицы сразу после ключевого слова DELETE. В противном случае сервер вернет синтаксическую ошибку:


DELETE ОстаткиТМЦ
FROM $Регистр.ОстаткиТМЦ AS ОстаткиТМЦ
INNER JOIN $Справочник.Номенклатура AS Номенклатура 
    ON ОстаткиТМЦ.$ОстаткиТМЦ.Номенклатура = Номенклатура.ID
WHERE Номенклатура.ISMARK = 1

Вариант 2: Удаление через подзапрос IN

Второй подход использует фильтрацию по списку идентификаторов. Алиас для целевой таблицы здесь не требуется:


DELETE FROM $Регистр.ОстаткиТМЦ
WHERE $ОстаткиТМЦ.Номенклатура IN (
    SELECT Номенклатура.ID
    FROM $Справочник.Номенклатура AS Номенклатура
    WHERE Номенклатура.ISMARK = 1
)

Оптимизатор SQL Server в большинстве случаев построит для обоих вариантов идентичный план выполнения (Join). Однако при удалении огромных массивов данных (от десятков тысяч строк) выполнение единой транзакции может вызвать эскалацию блокировок всей таблицы и переполнение журнала транзакций (LDF). Для высоконагруженных систем безопаснее выполнять удаление порциями в цикле:


WHILE 1 = 1
BEGIN
    DELETE TOP (5000) ОстаткиТМЦ
    FROM $Регистр.ОстаткиТМЦ AS ОстаткиТМЦ
    INNER JOIN $Справочник.Номенклатура AS Номенклатура 
        ON ОстаткиТМЦ.$ОстаткиТМЦ.Номенклатура = Номенклатура.ID
    WHERE Номенклатура.ISMARK = 1;

    IF @@ROWCOUNT = 0
        BREAK;
END

Опасности прямого удаления и пересчет итогов

Проанализируем последствия прямого удаления данных из таблиц СУБД в обход ядра 1С 7.7. Попытка просто выполнить DELETE из RA и RG скрывает в себе серьезные архитектурные риски:

  1. Рассинхронизация точки актуальности (ТА) и периодических итогов: в 1С 7.7 текущие остатки на ТА рассчитываются как сумма последнего закрытого периода из таблицы итогов (RG) плюс движения текущего периода из таблицы движений (RA). Ручное удаление строк из обеих таблиц почти гарантированно приводит к расхождению математического баланса. Единственный надежный способ восстановить консистентность — пересчитать итоги (штатным «Тестированием и исправлением», пересчетом в режиме «Монопольно» или специализированными обработками полного пересчета регистров).
  2. Битовая маска документов (ACTFLAGS в 1SJOURN): в общем журнале базы данных каждый проведенный документ содержит флаги активности по регистрам. Если движения из RA удалены напрямую, а маска активности в журнале осталась, система считает документ совершившим движения. При повторном проведении или отмене проведения такого документа возникнут разрывы итогов или непредсказуемые ошибки.
  3. Связь с табличными частями документов: удаление движений из регистра не удаляет саму номенклатуру из строк документов (таблицы DTxxxx). Штатная обработка «Удаление помеченных объектов» все равно не позволит физически стереть элементы номенклатуры, так как платформа найдет ссылки на них в проведенных и непроведенных документах.

Таким образом, наиболее безопасная последовательность действий при регламентной зачистке регистров выглядит так: удалить записи только из таблицы движений (RAxxxx), после чего выполнить полный пересчет итогов регистра штатными средствами или административной обработкой, позволив платформе самостоятельно сформировать чистые и корректные срезы в таблице итогов.

← На главную