Переезд с файловой версии базы данных 1С:Предприятие на клиент-серверный вариант (MS SQL Server) — процедура стандартная, но часто сопровождающаяся неприятными сюрпризами. Одной из самых «популярных» проблем является ошибка «Попытка вставки неуникального значения в уникальный индекс». Система сообщает об этом на этапе загрузки файла .dt в пустую SQL-базу. Давайте разберем по шагам, почему это происходит и как вылечить базу, когда обычные запросы не показывают дублей.
Для начала проанализируем природу ошибки. Файловая СУБД 1С довольно лояльно относится к некоторым нарушениям логической целостности данных. Например, она может позволить записать в регистр сведений две записи с абсолютно одинаковыми измерениями, если произошел сбой в транзакции или некорректно сработал какой-то «шаманский» скрипт. MS SQL Server, напротив, крайне строг к уникальности индексов. Когда платформа 1С пытается создать индекс по полям, где физически есть дубли, SQL блокирует эту операцию, и загрузка базы прерывается.
В нашем случае ошибка указывает на таблицу _InfoRg22483_ByPeriod_TRN. Проанализируем это имя. Суффикс _ByPeriod_TRN говорит о том, что это индекс по полям «Период», «Регистратор» и «Номер строки». Такой индекс создается для периодических регистров сведений, у которых установлена периодичность «В пределах позиции регистратора».
Чтобы понять, какой именно регистр вызывает проблему, воспользуемся программным методом ПолучитьСтруктуруХраненияБазыДанных(). Рассмотрим пример кода, который поможет сопоставить имя таблицы SQL с объектом метаданных 1С:
Структура = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаТТ Из Структура Цикл
Если СтрокаТТ.ИмяТаблицыХранения = "_InfoRg22483" Тогда
Сообщить("Это объект: " + СтрокаТТ.ИмяТаблицы);
КонецЕсли;
КонецЦикла;
В рассматриваемой ситуации выяснилось, что проблемная таблица принадлежит регистру сведений СписанныеТовары. Это важный регистр в конфигурации «Управление производственным предприятием 1.3» (УПП), который активно используется при партионном учете и проведении по партиям.
Первым делом мы попытаемся найти дублирующие записи стандартным запросом. Раз индекс ругается на уникальность комбинации Период + Регистратор + НомерСтроки, составим следующий проверочный запрос:
ВЫБРАТЬ
СписанныеТовары.Период КАК Период,
СписанныеТовары.Регистратор КАК Регистратор,
СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента,
СУММА(1) КАК КоличествоДублей
ИЗ
РегистрСведений.СписанныеТовары КАК СписанныеТовары
СГРУППИРОВАТЬ ПО
СписанныеТовары.Период,
СписанныеТовары.Регистратор,
СписанныеТовары.НомерСтрокиДокумента
ИМЕЮЩИЕ
СУММА(1) > 1
Важный нюанс: часто бывает так, что этот запрос возвращает пустой результат, хотя ошибка при загрузке в SQL сохраняется. Почему так происходит? Выясним причину: механизм исполнения запросов 1С в файловой базе может «отсеивать» записи с битыми ссылками (когда в поле Регистратор записан идентификатор типа документа, которого нет в конфигурации). Однако при выгрузке в .dt эти записи попадают в файл как «сырые» данные, и при вставке в SQL вызывают конфликт.
Если тестирование и исправление (ТиИ) и утилита chdbfl.exe не помогли, а запрос не видит дублей, проанализируем проверенный метод «XML-кольца». Это решение заключается в том, чтобы временно вывести данные из базы, очистить таблицу и загрузить их обратно уже средствами SQL-версии.
Разберем алгоритм по шагам:
ВыгрузкаЗагрузкаДанныхXML.epf (ее можно найти на диске ИТС). Выбираем только один наш проблемный регистр — СписанныеТовары. Выгружаем данные в файл.
Набор = РегистрыСведений.СписанныеТовары.СоздатьНаборЗаписей();
Набор.Записать(); // Записываем пустой набор, что физически очищает таблицу
.dt и загружаем ее на SQL-сервер. На этот раз загрузка должна пройти без ошибок индексации.ВыгрузкаЗагрузкаДанныхXML.epf загружаем ранее созданный файл.Почему это работает? При записи данных через механизмы XML платформа 1С использует стандартные методы записи наборов записей. Если в файле XML были записи, нарушающие уникальность, то при записи набора платформа либо автоматически их объединит, либо перезапишет, тем самым приведя данные к консистентному виду, который приемлем для SQL.
После того как данные возвращены в базу, мы должны убедиться, что учет не пострадал. Рассмотрим, на что обратить внимание:
Во-первых, регистр СписанныеТовары в УПП тесно связан с проведением по партиям. Рекомендуем запустить Тестирование и исправление с включенной опцией «Пересчет итогов». Это позволит системе актуализировать все внутренние таблицы итогов.
Во-вторых, проанализируем ситуацию с «битыми» ссылками. Если после загрузки из XML вы обнаружили в регистре записи с объектом <Объект не найден>, это означает, что оригинальные документы-регистраторы были удалены ранее, а записи в регистре «зависли». В идеале такие записи нужно удалить, чтобы они не искажали себестоимость товаров.
Если вы не хотите очищать весь регистр, можно попробовать найти конкретные «кривые» записи с помощью сторонних инструментов, таких как Tool1CD. Проанализируем этот путь: эта утилита позволяет открывать файл 1Cv8.1CD напрямую и просматривать физические таблицы. Выгрузив таблицу _InfoRg22483 в формат CSV или Excel, вы сможете с помощью простых фильтров или сводных таблиц найти строки с дублирующимися значениями в колонках _Period, _RecorderTRef, _RecorderRRef и _LineNo.
Однако метод с XML является более «штатным» с точки зрения платформы 1С и гарантирует, что структура данных останется целостной.
Выяснив причину и применив метод перезаписи данных через XML, мы успешно обходим ограничения SQL-индексов и получаем чистую, рабочую базу данных в клиент-серверном варианте.