Как исправить дублирование записей в таблице _1SCRDOC и ошибку уникальности индекса на SQL в 1С 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе с SQL-версией 1С:Предприятие 7.7 администраторы и программисты часто сталкиваются с неприятной ситуацией: во время процедуры «Тестирование и исправление» (ТиС) на этапе «Пересчет служебных записей» система выдает ошибку о нарушении уникальности индекса в таблице _1SCRDOC. Попытки просто удалить графу отбора и добавить её заново обычно не помогают — при следующем пересчете 1С снова генерирует дубликаты. В этой статье мы подробно разберем, почему это происходит и как окончательно вылечить базу данных.

Анализируем причину возникновения дублей

Для начала проанализируем структуру таблицы _1SCRDOC. Эта таблица отвечает за хранение информации о графах отбора и структуре подчиненности документов. В ней существует уникальный индекс, построенный по полям MDID (идентификатор графы отбора), PARENTVAL (идентификатор родительского объекта) и CHILDID (идентификатор подчиненного документа).

Рассмотрим типичный пример дублирующихся строк, который видит пользователь в SQL-запросе:


ROW_ID    MDID     PARENTVAL     CHILD_DATE_TIME_IDDOC        CHILDID     FLAGS
2058429   48780    B1  IA  1CDZ  20190930EAEAY8 SL0T          SL0T        1
2078352   48780    B1  IA  1CDZ  20190930EAGG40 SL0T          SL0T        8

Обратим внимание на важные детали: MDID, PARENTVAL и CHILDID идентичны. Однако значения в полях CHILD_DATE_TIME_IDDOC и FLAGS различаются. Выясним, что означают эти поля:

Суть проблемы: Процедура пересчета в 1С сканирует разные источники данных. Если время документа в журнале (_1SJOURN) не совпадает со временем в таблице проводок (_1SENTRY) или операций (_1SOPER) хотя бы на долю секунды, платформа считает их разными событиями и пытается вставить две разные записи в _1SCRDOC. Но так как ключевые поля (графа, родитель, документ) одинаковые, SQL Server блокирует вставку второй записи из-за нарушения уникальности индекса.

Способ 1: Исправление через перепроведение документов

Самый простой, но «медленный» способ решения проблемы — это найти документы, у которых есть расхождения, и перепровести их. При перепроведении платформа автоматически синхронизирует время во всех связанных таблицах, записывая актуальное значение DATE_TIME_IDDOC из журнала в проводки.

Выясним, как найти такие документы. Мы можем использовать запрос к базе данных, чтобы сравнить время в журнале и время в таблице _1SCRDOC, где FLAGS = 8. Если они отличаются — этот документ является кандидатом на перепроведение. После этого необходимо повторно запустить ТиС для пересчета служебных данных.

Способ 2: Автоматизированное лечение с использованием 1С++

Если документов много или период закрыт для редактирования, мы можем воспользоваться программным методом. Рассмотрим пример функции на языке 1С с использованием внешней компоненты 1С++, которая находит расхождения и исправляет поле CHILD_DATE_TIME_IDDOC в таблице _1SCRDOC, подтягивая верное значение из журнала документов.


Функция ВылечитьСтруктуру(прмДанные, прмЗапрос)
    Перем Результат, ТекстЗапроса, Док;    
    Результат = Нет;
    
    Если ПустоеЗначение(прмДанные.Документ) = 1 Тогда
        Возврат Результат;
    КонецЕсли;
    
    Док = СоздатьОбъект("Документ");
    Если Док.НайтиДокумент(прмДанные.Документ) = 1 Тогда
        Если Док.Блокировка(1) = 1 Тогда
            ТекстЗапроса = "
            |UPDATE _1SCRDOC 
            |    SET CHILD_DATE_TIME_IDDOC = Журнал.DATE_TIME_IDDOC
            |FROM _1SCRDOC Отбор
            |INNER JOIN _1SJOURN AS Журнал With (NOLOCK) ON (Журнал.IDDOC = Отбор.CHILDID) AND (Журнал.IDDOC = :Документ_подч)
            |WHERE
            |    (Отбор.ROW_ID = :НомерСтроки) 
            |    AND (Отбор.PARENTVAL = :Родитель) 
            |    AND (Отбор.CHILD_DATE_TIME_IDDOC <> Журнал.DATE_TIME_IDDOC)
            |    AND (Отбор.CHILDID = :Документ_подч)
            |";
            прмЗапрос.УстановитьТекстовыйПараметр("НомерСтроки", прмДанные.ROW_ID);
            прмЗапрос.УстановитьТекстовыйПараметр("Родитель", прмДанные.ЗначениеОтбора);
            прмЗапрос.УстановитьТекстовыйПараметр("Документ_подч", прмДанные.Документ_подч);
            
            Попытка
                прмЗапрос.ВыполнитьИнструкцию(ТекстЗапроса);
                Результат = Да;
                Сообщить("Починили документ: " + Док.ТекущийДокумент());
            Исключение
                Сообщить("Ошибка при лечении структуры: " + Лев(ОписаниеОшибки(), 200));
            КонецПопытки;
            Док.Блокировка(0);
        КонецЕсли;
    КонецЕсли;
    Возврат Результат;
КонецФункции

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

Способ 3: Прямая синхронизация таблиц через SQL (рекомендуемый)

Наиболее эффективным и правильным с точки зрения целостности БД методом является синхронизация времени документа во всех таблицах-источниках. Мы должны гарантировать, что во всех таблицах, где есть поле DATE_TIME_IDDOC, оно совпадает со значением в главном журнале _1SJOURN.

Проанализируем шаги для выполнения этой операции:

  1. Синхронизация таблицы проводок: Выполняем SQL-запрос, который обновит время в _1SENTRY на основании _1SJOURN.
    
    UPDATE _1SENTRY
    SET DATE_TIME_IDDOC = J.DATE_TIME_IDDOC
    FROM _1SENTRY E
    INNER JOIN _1SJOURN J ON E.IDDOC = J.IDDOC
    WHERE E.DATE_TIME_IDDOC <> J.DATE_TIME_IDDOC
    
  2. Синхронизация таблицы операций: Аналогично поступаем с таблицей _1SOPER.
    
    UPDATE _1SOPER
    SET DATE_TIME_IDDOC = J.DATE_TIME_IDDOC
    FROM _1SOPER O
    INNER JOIN _1SJOURN J ON O.IDDOC = J.IDDOC
    WHERE O.DATE_TIME_IDDOC <> J.DATE_TIME_IDDOC
    
  3. Очистка дублей в _1SCRDOC: После того как источники данных приведены к единому знаменателю, можно просто очистить таблицу _1SCRDOC (с помощью команды TRUNCATE TABLE _1SCRDOC или через удаление конкретных строк) и запустить пересчет служебных данных в 1С. Поскольку время теперь везде одинаковое, дубликаты больше не возникнут.

Важные замечания по безопасности

Перед выполнением любых прямых манипуляций с SQL-таблицами обязательно сделайте резервную копию базы данных. Работа напрямую с таблицами 1С 7.7 требует осторожности. Также убедитесь, что в момент выполнения запросов в базе нет активных пользователей, чтобы избежать блокировок и конфликтов доступа.

Подведем итог: Ошибка дублирования в _1SCRDOC — это лишь симптом «рассинхрона» времени документа между журналом и его проводками. Устранив причину через SQL-синхронизацию или перепроведение, вы избавитесь от ошибок при тестировании и исправлении базы.

← На главную