При работе с большими объемами данных (сотни миллионов записей) разработчики часто прибегают к прямой загрузке данных в таблицы SQL Server, минуя объектную модель 1С. Однако на этом пути можно столкнуться с парадоксальной ситуацией: при попытке вставки записей SQL Server возвращает ошибку "Повторяющееся значение ключа", хотя предварительная проверка данных с помощью оператора DISTINCT по всем измерениям утверждает, что все строки уникальны. При этом ручной ввод записи с тем же ключом через интерфейс 1С проходит успешно.
Рассмотрим детально, почему возникают "невидимые" дубли, проанализируем технические нюансы хранения данных в 1С и выясним, как правильно диагностировать и устранить эту проблему.
Одной из наиболее частых причин является разница в настройках Collation (параметрах сравнения и сортировки) между исходной таблицей с данными и целевой базой 1С. В среде 1С базы данных практически всегда создаются с регистронезависимой сортировкой (Case-Insensitive), например, Cyrillic_General_CI_AS.
Проанализируем ситуацию: если в вашем источнике данных есть две строки — "Текст" и "ТЕКСТ", то с точки зрения SQL Server в базе с регистрозависимой сортировкой (CS) это разные значения. Запрос SELECT DISTINCT вернет их как две отдельные записи. Однако целевая таблица 1С, имеющая настройку CI (Case-Insensitive), считает их идентичными. При попытке вставки второй строки возникнет конфликт уникального индекса.
Для диагностики этой проблемы выполним проверку данных с принудительным указанием нужной сортировки:
SELECT Измерение1, Измерение2, Измерение3, Измерение4, Измерение5, COUNT(*)
FROM ИсходнаяТаблица
GROUP BY Измерение1, Измерение2, Измерение3, Измерение4, Измерение5
COLLATE Cyrillic_General_CI_AS
HAVING COUNT(*) > 1
SQL Server имеет специфическую особенность сравнения строк, которая регулируется настройкой SET ANSI_PADDING. В некоторых режимах работы при сравнении значений в строковых полях (особенно типа VARCHAR или NVARCHAR) SQL Server игнорирует пробелы в конце строки.
Представим две записи: "Значение" и "Значение " (с пробелом в конце). Для оператора DISTINCT они могут выглядеть как разные записи (в зависимости от контекста выполнения), но при вставке в PRIMARY KEY или UNIQUE INDEX система может расценить их как дубли. Чтобы исключить эту причину, проанализируем данные на наличие лишних символов с помощью функции DATALENGTH() или попробуем нормализовать строки перед загрузкой:
-- Проверка на наличие строк, которые станут одинаковыми после обрезки пробелов
SELECT LTRIM(RTRIM(Измерение1)), COUNT(*)
FROM ИсходнаяТаблица
GROUP BY LTRIM(RTRIM(Измерение1))
HAVING COUNT(*) > 1
Важно помнить, что структура таблицы регистра сведений в SQL Server не всегда ограничивается только теми измерениями, которые мы видим в конфигураторе 1С. Платформа добавляет служебные поля, которые входят в состав первичного ключа (Clustered Index).
_Period. Если вы загружаете данные без учета времени или используете константную дату, убедитесь, что уникальность соблюдается именно в связке с этим полем._RecorderTRef (тип ссылки) и _RecorderRRef (идентификатор объекта).Платформа 1С использует тип NVARCHAR для хранения строк, что обеспечивает поддержку Unicode. Если ваш источник данных использует обычный VARCHAR, то в процессе импорта происходит неявная конвертация. Разберем риски: при преобразовании из одной кодировки в Unicode разные специфические символы (например, специфические знаки тире или символы из разных национальных алфавитов) могут превратиться в один и тот же символ (часто в знак вопроса "?"). Это создаст дубль в ключевых полях, которого не было в исходнике.
Посмотрим на пример проверки таких данных перед загрузкой:
-- Проверка уникальности после приведения к типу целевой таблицы
SELECT CAST(Измерение1 AS NVARCHAR(100)), COUNT(*)
FROM ИсходнаяТаблица
GROUP BY CAST(Измерение1 AS NVARCHAR(100))
HAVING COUNT(*) > 1
При использовании мастера импорта (Import/Export Wizard) или команды BULK INSERT данные загружаются пакетами (batches). Если процесс импорта был прерван и запущен заново без предварительной очистки (TRUNCATE) целевой таблицы, ошибка дубликата может возникнуть из-за пересечения новых данных с теми, что уже успели записаться в предыдущей итерации.
Чтобы окончательно выяснить причину, выполним комплексный запрос, который сгруппирует данные именно по тем правилам, по которым построен индекс в 1С. Это позволит увидеть "проблемные" строки, которые система считает одинаковыми:
SELECT
LTRIM(RTRIM(Измерение1)) COLLATE Cyrillic_General_CI_AS,
LTRIM(RTRIM(Измерение2)) COLLATE Cyrillic_General_CI_AS,
-- ... добавьте все измерения
COUNT(*)
FROM ВашаТаблицаИсточника
GROUP BY
LTRIM(RTRIM(Измерение1)) COLLATE Cyrillic_General_CI_AS,
LTRIM(RTRIM(Измерение2)) COLLATE Cyrillic_General_CI_AS
HAVING COUNT(*) > 1
Если этот запрос вернет строки, значит, ваша исходная выборка содержит данные, которые 1С считает идентичными из-за регистра или пробелов. Если запрос пуст, но ошибка сохраняется, следует проверить наличие данных в целевой таблице 1С — возможно, записи с такими ключами там уже присутствуют.
Важный момент: Прямая запись в таблицы SQL минуя механизмы 1С — это крайняя мера. Она не обновляет итоги, не инициирует срабатывание обработчиков событий и может привести к нарушению логической целостности базы. Используйте этот метод только при полной уверенности в своих действиях и после выполнения резервного копирования.