Как исправить ошибку «Попытка вставки неуникального значения в уникальный индекс» при переносе базы 1С на SQL?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Выясняем причину конфликта

Для начала проанализируем природу ошибки. Файловая СУБД 1С довольно лояльно относится к некоторым нарушениям логической целостности данных. Например, она может позволить записать в регистр сведений две записи с абсолютно одинаковыми измерениями, если произошел сбой в транзакции или некорректно сработал какой-то «шаманский» скрипт. MS SQL Server, напротив, крайне строг к уникальности индексов. Когда платформа 1С пытается создать индекс по полям, где физически есть дубли, SQL блокирует эту операцию, и загрузка базы прерывается.

В нашем случае ошибка указывает на таблицу _InfoRg22483_ByPeriod_TRN. Проанализируем это имя. Суффикс _ByPeriod_TRN говорит о том, что это индекс по полям «Период», «Регистратор» и «Номер строки». Такой индекс создается для периодических регистров сведений, у которых установлена периодичность «В пределах позиции регистратора».

Шаг 1. Идентификация проблемного объекта

Чтобы понять, какой именно регистр вызывает проблему, воспользуемся программным методом ПолучитьСтруктуруХраненияБазыДанных(). Рассмотрим пример кода, который поможет сопоставить имя таблицы SQL с объектом метаданных 1С:


Структура = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаТТ Из Структура Цикл
    Если СтрокаТТ.ИмяТаблицыХранения = "_InfoRg22483" Тогда
        Сообщить("Это объект: " + СтрокаТТ.ИмяТаблицы);
    КонецЕсли;
КонецЦикла;

В рассматриваемой ситуации выяснилось, что проблемная таблица принадлежит регистру сведений СписанныеТовары. Это важный регистр в конфигурации «Управление производственным предприятием 1.3» (УПП), который активно используется при партионном учете и проведении по партиям.

Шаг 2. Поиск дублей запросом (и почему это не всегда помогает)

Первым делом мы попытаемся найти дублирующие записи стандартным запросом. Раз индекс ругается на уникальность комбинации Период + Регистратор + НомерСтроки, составим следующий проверочный запрос:


ВЫБРАТЬ
    СписанныеТовары.Период КАК Период,
    СписанныеТовары.Регистратор КАК Регистратор,
    СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента,
    СУММА(1) КАК КоличествоДублей
ИЗ
    РегистрСведений.СписанныеТовары КАК СписанныеТовары
СГРУППИРОВАТЬ ПО
    СписанныеТовары.Период,
    СписанныеТовары.Регистратор,
    СписанныеТовары.НомерСтрокиДокумента
ИМЕЮЩИЕ
    СУММА(1) > 1

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

Шаг 3. Радикальное, но эффективное решение через XML

Если тестирование и исправление (ТиИ) и утилита chdbfl.exe не помогли, а запрос не видит дублей, проанализируем проверенный метод «XML-кольца». Это решение заключается в том, чтобы временно вывести данные из базы, очистить таблицу и загрузить их обратно уже средствами SQL-версии.

Разберем алгоритм по шагам:

  1. Выгрузка данных в XML. Воспользуемся стандартной обработкой ВыгрузкаЗагрузкаДанныхXML.epf (ее можно найти на диске ИТС). Выбираем только один наш проблемный регистр — СписанныеТовары. Выгружаем данные в файл.
  2. Очистка регистра в файловой базе. Чтобы очистить регистр, выполним короткий код в обработке:
    
    Набор = РегистрыСведений.СписанныеТовары.СоздатьНаборЗаписей();
    Набор.Записать(); // Записываем пустой набор, что физически очищает таблицу
    
  3. Миграция на SQL. Теперь, когда «битый» регистр пуст, выгружаем базу в .dt и загружаем ее на SQL-сервер. На этот раз загрузка должна пройти без ошибок индексации.
  4. Обратная загрузка данных. Запускаем SQL-базу в режиме «Предприятие» и через ту же обработку ВыгрузкаЗагрузкаДанныхXML.epf загружаем ранее созданный файл.

Почему это работает? При записи данных через механизмы XML платформа 1С использует стандартные методы записи наборов записей. Если в файле XML были записи, нарушающие уникальность, то при записи набора платформа либо автоматически их объединит, либо перезапишет, тем самым приведя данные к консистентному виду, который приемлем для SQL.

Проверка результатов и профилактика

После того как данные возвращены в базу, мы должны убедиться, что учет не пострадал. Рассмотрим, на что обратить внимание:

Во-первых, регистр СписанныеТовары в УПП тесно связан с проведением по партиям. Рекомендуем запустить Тестирование и исправление с включенной опцией «Пересчет итогов». Это позволит системе актуализировать все внутренние таблицы итогов.

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

Альтернативные способы поиска (для продвинутых)

Если вы не хотите очищать весь регистр, можно попробовать найти конкретные «кривые» записи с помощью сторонних инструментов, таких как Tool1CD. Проанализируем этот путь: эта утилита позволяет открывать файл 1Cv8.1CD напрямую и просматривать физические таблицы. Выгрузив таблицу _InfoRg22483 в формат CSV или Excel, вы сможете с помощью простых фильтров или сводных таблиц найти строки с дублирующимися значениями в колонках _Period, _RecorderTRef, _RecorderRRef и _LineNo.

Однако метод с XML является более «штатным» с точки зрения платформы 1С и гарантирует, что структура данных останется целостной.

Выяснив причину и применив метод перезаписи данных через XML, мы успешно обходим ограничения SQL-индексов и получаем чистую, рабочую базу данных в клиент-серверном варианте.

← На главную