N'Șc 'ha considerato la chiave duplicata di N'C' usando le regole di confronto Latin1_General_CI_AS


11

Ho una tabella con una chiave univoca che include una NVARCHAR(50)colonna (corretta o no, ma c'è). Quindi, quando si tenta di inserire Șco C(non importa l'ordine dell'inserto) si rompe sul secondo inserto a causa di problemi di confronto. Ecco l'errore:

(1 riga (e) interessata) Messaggio 2601, Livello 14, Stato 1, Riga 16 Impossibile inserire la riga chiave duplicata nell'oggetto 'dbo.testT' con indice univoco 'IX_TestT'. Il valore della chiave duplicata è (C).

Seleziona resi:

inserisci qui la descrizione dell'immagine

Fascicolazione predefinita del database è Latin1_General_CI_AS. Trascorso del tempo a cercare come risolverlo, senza cambiare troppo la struttura già esistente, ma non riesco a trovare un modo per farlo funzionare. Ho provato diverse raccolte e combinazioni, tutto fallisce. Leggi ( qui e qui ) le espansioni dei personaggi e così via, ancora bloccato. Ecco un codice di esempio che sto usando per replicare il problema, sentiti libero di modificare e raccomandare qualsiasi cosa possa aiutare a risolvere questo problema.

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;

Risposte:


10

Il problema è che le vecchie regole di confronto di SQL Server (ovvero quelle con nomi che iniziano con SQL_) e le prime due versioni delle regole di confronto di Windows (le 80serie fornite con SQL Server 2000 e non hanno un numero di versione nel nome e le 90serie che fornito con SQL Server 2005) mancano i pesi di ordinamento per molti personaggi. Ciò è stato principalmente corretto a partire dalle 100serie Collation fornite con SQL Server 2008.

Come si può vedere negli esempi seguenti, il Șcarattere corrisponde a una stringa vuota quando si utilizzano regole di confronto non binarie, versione 80 o 90 (e regole di confronto di SQL Server) poiché entrambi hanno lo stesso peso di ordinamento: 0. Niente. Nada. Ciò significa che quando si confronta N'Șc'con N'C'(usando pre-serie 100 Collations), si sta davvero confrontando N'c'con N'C'(test n. 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)

Quindi, sfortunatamente, dovrai rilasciare il PK, modificare la colonna per avere un Collation a 100 livelli (ad es. Latin1_General_100_CI_AS_SC) E quindi ricreare il PK. Si prega di notare che la differenza di regole di confronto che ha suggerito dagli attuali regole di confronto è sia il 100 e il _SCalla fine, che le permette di gestire correttamente i caratteri supplementari.

Questo non significa che devi:

  1. cambia le regole di confronto di altre tabelle (a meno che non abbiano la stessa configurazione di NVARCHARnel PK)
  2. modificare le regole di confronto predefinite del database. Il problema principale nel non modificare le regole di confronto del DB è che ci sarà una differenza di comportamento tra fare table.column = N'Ș'e @variable = N'Ș'poiché variabili e valori letterali di stringhe utilizzano le regole di confronto predefinite del database.

Per ulteriori esempi di questo comportamento, vedere la sezione "Personaggi supplementari" del mio post di blog seguente:

Il codice Uni: la ricerca del vero elenco di caratteri validi per identificatori T-SQL, parte 3 di 2 (identificatori delimitati)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.