При работе с «древними» конфигурациями на платформе 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-база уже недоступна или необратимо повреждена.
Проанализируем ситуацию: почему в базе появляются одинаковые IDDOC? При достижении лимита в 2 Гб файловая система или движок базы данных перестает корректно адресовать новые записи. В результате 1С может записать новый документ поверх старого или создать запись с некорректным индексом. При выгрузке данных в текстовый файл 1Cv7.dat платформа считывает всё подряд, и в секции таблицы 1SJOURN оказываются две (или более) строки с идентичным идентификатором документа. При загрузке в SQL данные сначала вставляются в таблицу, а затем запускается процесс создания индексов. На этапе CREATE UNIQUE INDEX система обнаруживает дубль и откатывает транзакцию.
Один из самых изящных и современных способов решения проблемы — использование триггеров на стороне 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С завершить загрузку данных, а последующая команда создания уникального индекса выполнится без ошибок, так как дублей в таблице уже не будет.
Если вы не хотите использовать SQL-триггеры, можно попробовать восстановить «промежуточную» работоспособную DBF-базу. Существует специализированная библиотека dbeng32.dll (разработка Wirth), которая снимает ограничение в 2 Гб для файлов таблиц. Рассмотрим этот путь по шагам:
1sjourn.dbf сможет вырасти до 3-4 Гб без ошибок.1SJOURN.Этот метод хорош тем, что позволяет визуально проконтролировать, какие именно документы задублировались, и принять решение: какой из них «настоящий», а какой — мусорный.
Рассмотрим ситуацию, когда база слишком велика для любых манипуляций с 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.dds (структура базы данных), сделав индекс по полю IDDOC неуникальным. Однако это «костыль», который может привести к неработоспособности некоторых механизмов платформы (например, метода НайтиДокумент()).UNIQUE. Это позволит загрузить базу «как есть», а потом уже средствами SQL-запросов вычистить дубли и создать индекс вручную.Важно: Перед любыми манипуляциями обязательно делайте резервную копию файла 1Cv7.dat. Работа с «убитыми» базами 7.7 требует терпения, так как пересчет итогов после загрузки в SQL на больших объемах может занимать десятки часов.
Подводя итог, наиболее надежным способом для программиста является использование SQL-триггеров (Решение 1), так как это автоматизирует процесс и исключает человеческий фактор при ручной правке гигабайтных текстовых файлов. Если же база нужна «здесь и сейчас» в файловом варианте — используйте dbeng32.dll.