N'Șc 'вважається дублікатом ключа N'C', використовуючи порівняння Latin1_General_CI_AS


11

У мене є таблиця з унікальним ключем, що містить NVARCHAR(50)стовпчик (правильний чи ні, але чи є). Отже, при спробі вставити Șcабо C(не має значення порядок вставки) він перерветься на 2-й вставці через проблеми зіставлення. Ось помилка:

(1 ряд (и) зачіпають) Msg 2601, рівень 14, стан 1, рядок 16 Неможливо вставити повторюваний ключовий рядок в об’єкт 'dbo.testT' з унікальним індексом 'IX_TestT'. Значення дублюючого ключа - (C).

Вибрати прибутки:

введіть тут опис зображення

Порівняння бази даних за замовчуванням Latin1_General_CI_AS. Витратили деякий час на те, як його вирішити, не змінюючи занадто сильно існуючої структури, але не можете знайти спосіб працювати. Пробували різні зібрання та комбінації, все провалюється. Читайте ( тут і тут ) про розширення персонажів тощо, як і раніше застрягли. Ось зразок коду, який я використовую для тиражування проблеми, не соромтесь змінювати та рекомендувати все, що могло б допомогти вирішити цю проблему.

CREATE TABLE testT (
    [Default_Collation]     [NVARCHAR] (50) COLLATE DATABASE_DEFAULT,
    [Latin1_General_CI_AS]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AS,
    [Latin1_General_CI_AI]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AI,
    [SQL_Collation]         [NVARCHAR] (50) COLLATE SQL_Latin1_General_CP1_CI_AS);
CREATE UNIQUE CLUSTERED INDEX [IX_TestT] ON [dbo].[testT] ([Default_Collation])
ON [PRIMARY]
GO

INSERT INTO testT
SELECT  N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc'   --COLLATE Latin1_General_CI_AS

INSERT INTO testT
SELECT  N'C'    --COLLATE Latin1_General_CI_AS 
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE SQL_Latin1_General_CP1_CI_AS

SELECT * FROM testT;

DROP TABLE testT;

Відповіді:


10

Проблема полягає в тому, що стара колекція SQL Server (тобто ті, з іменами яких починається SQL_) та перші дві версії Windows Collations ( 80серія, яка поставляється із SQL Server 2000 і не має номера версії в назві, та 90серія, яка прийшов із SQL Server 2005) не вистачає ваги сортування для великої кількості символів. Здебільшого це було виправлено, починаючи з 100серії Collations, що надійшла до SQL Server 2008.

Як ви бачите на наведених нижче прикладах, Șсимвол відповідає порожній рядку при використанні небінарних зібрань версій 80 або 90 (і зібрань SQL Server), оскільки вони мають однакову вагу сортування: 0. Нічого. Нада. Це означає , що при порівнянні N'Șc'з N'C'( з використанням попередньо серії 100 Collations), ви дійсно порівнюють N'c'з N'C'(тест № 1):

SELECT 1 WHERE N'Șc' = N'C' COLLATE Latin1_General_CS_AS;
-- no result (due to "c" and "C" being different case)

SELECT 2 WHERE N'Ș' = N'' COLLATE SQL_Latin1_General_CP1_CI_AS;
SELECT 3 WHERE N'Ș' = N'' COLLATE Latin1_General_CI_AS;

SELECT 4 WHERE N'Ș' = N'' COLLATE Latin1_General_BIN2;
-- no result (due to "Ș" still being a code point and empty string has no code points)

SELECT 5 WHERE N'Ș' = N'' COLLATE Latin1_General_100_CI_AS;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

SELECT 6 WHERE N'Ș' = N'' COLLATE Chinese_PRC_CI_AI;
SELECT 7 WHERE N'Ș' = N'' COLLATE Chinese_PRC_90_CI_AI;

SELECT 8 WHERE N'Ș' = N'' COLLATE Indic_General_90_CI_AI;
SELECT 9 WHERE N'Ș' = N'' COLLATE Indic_General_100_CI_AI;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

Тож, на жаль, вам потрібно буде скинути ПК, змінити стовпчик, щоб він був зібраний на 100 рівнів (наприклад Latin1_General_100_CI_AS_SC), а потім відтворити ПК. Будь ласка , зверніть увагу , що різниця в тому , що запропонувала параметри сортування з поточної сортування як 100 і_SC в кінці, що дозволяє йому правильно обробляти додаткові символи.

Це не означає, що вам потрібно:

  1. змінити зіставлення інших таблиць (якщо вони не мають однакових налаштувань NVARCHARу ПК)
  2. змінити зіставлення бази даних за замовчуванням Основна проблема з тим, щоб не змінювати Збір даних БД, полягає в тому, що буде різниця в поведінці між виконанням table.column = N'Ș'і @variable = N'Ș'оскільки змінні та рядкові літерали використовують Збір за замовчуванням Бази даних.

Щоб отримати додаткові приклади такої поведінки, перегляньте розділ «Додаткові символи» наступного мого блогу:

Уні-код: Пошук справжнього списку дійсних символів для ідентифікаторів T-SQL, частина 3 з 2 (Розмежовані ідентифікатори)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.