В процессе применения обновлений конфигурации базы данных или выполнения реструктуризации таблиц может возникнуть критическая ошибка СУБД 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).
Разберем природу возникновения этого сбоя, научимся расшифровывать бинарные данные из сообщения об ошибке и рассмотрим способы устранения проблемы.
Проанализируем механизм обновления таблиц на уровне СУБД:
NG (New Generation), переносит в нее данные из исходной таблицы и накладывает уникальные индексы._Acc..._ExtDim...) уже присутствуют поврежденные записи с одинаковым номером строки (_LineNo) или дублирующимся видом субконто для одного и того же счета, создание уникального индекса завершается аварийно.Посмотрим на структуру неуникального ключа из сообщения:
The duplicate key value is (0x9fa6f7570ab99fb74de12c6c94b7effe, 1, 0x870cef15904ca7e347798bbfc30f780b)
Значения в скобках соответствуют полям индекса табличной части:
0x9fa6f7570ab99fb74de12c6c94b7effe — 16-байтный бинарный идентификатор (_Account_IDRRef) проблемного счета.1 — номер строки табличной части (_LineNo), на которой произошло задвоение.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С. При перезаписи объекта платформа полностью удаляет старые физические строки табличной части в СУБД и формирует их заново с правильной сквозной нумерацией.
Если требуется выполнить перезапись программно, воспользуемся кодом:
// Получаем ссылку на счет по его идентификатору или коду
СчетОбъект = ПланыСчетов.Хозрасчетный.НайтиПоКоду("ПроблемныйКод").ПолучитьОбъект();
Если СчетОбъект <> Неопределено Тогда
// Запись объекта переформирует строки ТЧ в таблицах СУБД
СчетОбъект.Записать();
Сообщить("Счет успешно перезаписан!");
КонецЕсли;
Если в базе обнаружено множество поврежденных строк, перезаписывать каждый счет вручную может быть трудоемко. В таком случае поможет штатный механизм выгрузки:
.dt. Механизм выгрузки считывает данные объектов логически, нормализуя строки табличных частей.В критических ситуациях, когда запустить предприятие не удается, исправление можно выполнить прямым запросом к СУБД. Внимание: перед выполнением любых операций прямого изменения базы обязательно сделайте полную резервную копию.
Удалим лишнюю строку-дубль из исходной таблицы, оставив только уникальные записи:
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. Режим Реиндексация таблиц лишь обновляет существующее дерево индексов и не удаляет задвоенные строки из физических таблиц базы данных.