Как исправить ошибку неуникальных индексов при загрузке базы 1С 7.7 из архива в SQL

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

При работе с «древними» конфигурациями на платформе 1С:Предприятие 7.7 специалисты часто сталкиваются с критическим ограничением формата DBF — предельный размер одного файла не может превышать 2 Гб. Когда файл общего журнала 1sjourn.dbf или таблицы регистров приближаются к этому порогу, база начинает вести себя непредсказуемо: возникают ошибки записи, «вылеты» и, что самое неприятное, логические повреждения структуры данных. Попытка решить проблему «в лоб» через выгрузку в .zip (файл 1Cv7.dat) и последующую загрузку в MS SQL Server часто заканчивается ошибкой: CREATE UNIQUE INDEX terminated because a duplicate key was found for the object name 'dbo.1sjourn'.

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

Причина возникновения дублей при лимите 2 Гб

Проанализируем ситуацию: почему в базе появляются одинаковые IDDOC? При достижении лимита в 2 Гб файловая система или движок базы данных перестает корректно адресовать новые записи. В результате 1С может записать новый документ поверх старого или создать запись с некорректным индексом. При выгрузке данных в текстовый файл 1Cv7.dat платформа считывает всё подряд, и в секции таблицы 1SJOURN оказываются две (или более) строки с идентичным идентификатором документа. При загрузке в SQL данные сначала вставляются в таблицу, а затем запускается процесс создания индексов. На этапе CREATE UNIQUE INDEX система обнаруживает дубль и откатывает транзакцию.

Решение 1: Использование DDL-триггеров в SQL Server

Один из самых изящных и современных способов решения проблемы — использование триггеров на стороне SQL Server. Мы можем заставить сервер автоматически удалять дубликаты в тот момент, когда 1С создает таблицу и наполняет её данными, но еще не успела инициировать создание уникального индекса. Рассмотрим алгоритм реализации через DDL-триггер.

Нам необходимо создать триггер уровня базы данных, который будет отслеживать событие CREATE_TABLE. Как только 1С создаст таблицу _1sjourn (или dh*, если проблема в них), этот триггер создаст другой — DML-триггер — уже внутри самой таблицы для обработки вставляемых данных.

Пример кода для SQL Server для автоматической очистки дублей:


-- Создаем DDL-триггер для перехвата создания таблицы
CREATE TRIGGER trigg_table_create
ON DATABASE
FOR CREATE_TABLE  
AS
    -- Проверяем, что создается именно таблица общего журнала
    IF EVENTDATA().value('(/EVENT_INSTANCE[1]/ObjectName[1])', 'nvarchar(150)') = '_1sjourn'
    BEGIN
        EXEC (
            'CREATE TRIGGER tr_jrn_insert ON dbo._1sjourn
             AFTER INSERT 
             AS  
             BEGIN
                -- Удаляем дубликаты, оставляя только одну запись для каждого IDDOC
                DELETE FROM _1sjourn
                WHERE ROWID IN (
                    SELECT ROWID FROM (
                        SELECT ROWID, ROW_NUMBER() OVER (PARTITION BY IDDOC ORDER BY (SELECT NULL)) as RN
                        FROM _1sjourn
                    ) T WHERE T.RN > 1
                )
             END'
        )
    END
GO

Разберем, что происходит: при каждой вставке (AFTER INSERT) триггер будет анализировать таблицу и удалять лишние записи с одинаковыми IDDOC. Это позволит 1С завершить загрузку данных, а последующая команда создания уникального индекса выполнится без ошибок, так как дублей в таблице уже не будет.

Решение 2: Обход лимита 2 Гб и восстановление через DBF

Если вы не хотите использовать SQL-триггеры, можно попробовать восстановить «промежуточную» работоспособную DBF-базу. Существует специализированная библиотека dbeng32.dll (разработка Wirth), которая снимает ограничение в 2 Гб для файлов таблиц. Рассмотрим этот путь по шагам:

  1. Подготовка движка: Заменяем в каталоге программы 1С штатную библиотеку на модифицированную версию, поддерживающую большие файлы.
  2. Загрузка данных: Выполняем «Загрузку данных» из имеющегося архива в пустую папку (формат базы — DBF). Благодаря модифицированной библиотеке, файл 1sjourn.dbf сможет вырасти до 3-4 Гб без ошибок.
  3. Поиск и устранение дублей: После успешной загрузки открываем базу любой утилитой для работы с DBF (например, CDBF или через саму 1С обработкой) и ищем дубликаты в таблице 1SJOURN.
  4. Миграция: После того как база приведена в порядок в формате DBF, делаем новую выгрузку и уже её штатно загружаем в SQL Server.

Этот метод хорош тем, что позволяет визуально проконтролировать, какие именно документы задублировались, и принять решение: какой из них «настоящий», а какой — мусорный.

Решение 3: Прямое редактирование файла выгрузки 1Cv7.dat

Рассмотрим ситуацию, когда база слишком велика для любых манипуляций с DBF. В этом случае придется работать с самим файлом 1Cv7.dat. Это текстовый файл, но его размер может достигать десятков гигабайт, поэтому обычные редакторы его «не потянут».

Проанализируем структуру секции данных. Каждая таблица начинается с заголовка, а строки данных разделены символом |. Нам нужно найти дублирующиеся IDDOC. Выясним причину ошибки: загрузка обычно прерывается на конкретном документе. Мы можем воспользоваться советом из практики: запустить загрузку в SQL, дождаться ошибки и посмотреть, на каком этапе она произошла. Если данные не откатились полностью, в таблице _1sjourn можно увидеть последний загруженный IDDOC.

Для правки файла используем потоковые редакторы (например, sed в Linux/Cygwin) или скрипты на Python. Рассмотрим логику поиска:


# Пример логики на Python для поиска дублей в огромном файле
seen_ids = set()
with open('1Cv7.dat', 'r', encoding='cp1251') as f:
    for line in f:
        if '|' in line:
            parts = line.split('|')
            # IDDOC обычно является одним из первых полей в секции 1SJOURN
            iddoc = parts[1] 
            if iddoc in seen_ids:
                print(f"Найден дубль: {iddoc}")
            seen_ids.add(iddoc)

После нахождения дублей в 1Cv7.dat их можно либо удалить (аккуратно, соблюдая структуру строк), либо изменить IDDOC на заведомо уникальный. Однако помните, что IDDOC в 1С 7.7 — это 36-ричное число, и простое изменение одной цифры может нарушить связи с таблицами движений (регистрами).

Дополнительные советы по реанимации

Проанализируем еще несколько важных моментов, которые помогут при восстановлении:

Важно: Перед любыми манипуляциями обязательно делайте резервную копию файла 1Cv7.dat. Работа с «убитыми» базами 7.7 требует терпения, так как пересчет итогов после загрузки в SQL на больших объемах может занимать десятки часов.

Подводя итог, наиболее надежным способом для программиста является использование SQL-триггеров (Решение 1), так как это автоматизирует процесс и исключает человеческий фактор при ручной правке гигабайтных текстовых файлов. Если же база нужна «здесь и сейчас» в файловом варианте — используйте dbeng32.dll.

← На главную