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

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

В процессе применения обновлений конфигурации базы данных или выполнения реструктуризации таблиц может возникнуть критическая ошибка СУБД Microsoft SQL Server вида:

Cannot insert duplicate key row in object 'dbo._Acc4_ExtDim16919NG' with unique index '_Acc4_ExtDim16919_ByLineNoNG'. The duplicate key value is (0x9fa6f7570ab99fb74de12c6c94b7effe, 1, 0x870cef15904ca7e347798bbfc30f780b).

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

Почему возникает данная ошибка

Проанализируем механизм обновления таблиц на уровне СУБД:

  1. Процесс реструктуризации: когда платформа 1С изменяет структуру метаданных плана счетов или типов видов субконто, она создает временную копию таблицы с суффиксом NG (New Generation), переносит в нее данные из исходной таблицы и накладывает уникальные индексы.
  2. Физические дубли в базе: если в исходной табличной части видов субконто (_Acc..._ExtDim...) уже присутствуют поврежденные записи с одинаковым номером строки (_LineNo) или дублирующимся видом субконто для одного и того же счета, создание уникального индекса завершается аварийно.
  3. Причины появления дублей: такие нарушения целостности чаще всего вызваны аварийными сбоями сеансов во время записи счетов, ошибками сторонних обменов данными или ручным добавлением видов субконто в пользовательском режиме, совпавших с предопределенными типами из обновления.

Расшифровка сообщения об ошибке и поиск проблемного счета

Посмотрим на структуру неуникального ключа из сообщения:

The duplicate key value is (0x9fa6f7570ab99fb74de12c6c94b7effe, 1, 0x870cef15904ca7e347798bbfc30f780b)

Значения в скобках соответствуют полям индекса табличной части:

  1. 0x9fa6f7570ab99fb74de12c6c94b7effe — 16-байтный бинарный идентификатор (_Account_IDRRef) проблемного счета.
  2. 1 — номер строки табличной части (_LineNo), на которой произошло задвоение.
  3. 0x870cef15904ca7e347798bbfc30f780b — идентификатор вида субконто (_DimKind_IDRRef) из Плана видов характеристик.

Для точной идентификации объекта сопоставим имена таблиц СУБД с метаданными 1С с помощью функции ПолучитьСтруктуруХраненияБазыДанных():


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

Чтобы локализовать счет напрямую на сервере Microsoft SQL Server, выполним запрос:


SELECT * FROM dbo._Acc4 
WHERE _IDRRef = 0x9fa6f7570ab99fb74de12c6c94b7effe;

Также проверим наличие всех задвоенных строк в табличной части видов субконто:


SELECT _Account_IDRRef, _LineNo, COUNT(*) AS Дубли 
FROM dbo._Acc4_ExtDim16919 
GROUP BY _Account_IDRRef, _LineNo 
HAVING COUNT(*) > 1;

Способ 1. Перезапись счета в режиме 1С:Предприятие (рекомендуемый)

Самый безопасный и корректный способ восстановить целостность табличной части — перезаписать проблемный счет штатными средствами платформы 1С. При перезаписи объекта платформа полностью удаляет старые физические строки табличной части в СУБД и формирует их заново с правильной сквозной нумерацией.

  1. Открываем базу данных в режиме «1С:Предприятие» до выполнения реструктуризации.
  2. Находим счет, определенный на этапе поиска (например, по коду или наименованию).
  3. Открываем форму счета, проверяем состав табличной части Виды субконто на наличие задвоенных видов (например, дважды указан один и тот же вид субконто).
  4. Корректируем состав строк и нажимаем Записать и закрыть.

Если требуется выполнить перезапись программно, воспользуемся кодом:


// Получаем ссылку на счет по его идентификатору или коду
СчетОбъект = ПланыСчетов.Хозрасчетный.НайтиПоКоду("ПроблемныйКод").ПолучитьОбъект();
Если СчетОбъект <> Неопределено Тогда
    // Запись объекта переформирует строки ТЧ в таблицах СУБД
    СчетОбъект.Записать();
    Сообщить("Счет успешно перезаписан!");
КонецЕсли;

Способ 2. Выгрузка и загрузка информационной базы через .dt

Если в базе обнаружено множество поврежденных строк, перезаписывать каждый счет вручную может быть трудоемко. В таком случае поможет штатный механизм выгрузки:

  1. В Конфигураторе выбираем пункт меню Администрирование > Выгрузить информационную базу... и создаем файл .dt. Механизм выгрузки считывает данные объектов логически, нормализуя строки табличных частей.
  2. Создаем новую чистую базу данных на сервере СУБД.
  3. Загружаем полученный файл через Администрирование > Загрузить информационную базу....
  4. Повторяем процесс обновления конфигурации.

Способ 3. Удаление дублей средствами SQL

В критических ситуациях, когда запустить предприятие не удается, исправление можно выполнить прямым запросом к СУБД. Внимание: перед выполнением любых операций прямого изменения базы обязательно сделайте полную резервную копию.

Удалим лишнюю строку-дубль из исходной таблицы, оставив только уникальные записи:


WITH CTE AS (
    SELECT _Account_IDRRef, _LineNo,
           ROW_NUMBER() OVER (PARTITION BY _Account_IDRRef, _LineNo ORDER BY _Account_IDRRef) AS RowNum
    FROM dbo._Acc4_ExtDim16919
)
DELETE FROM CTE WHERE RowNum > 1;

После удаления дублирующей строки запустим процедуру обновления конфигурации в Конфигураторе заново — реструктуризация и наложение индекса _ByLineNoNG пройдут успешно.

Почему стандартное Тестирование и исправление (ТИИ) не помогает

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

← На главную