N'Șc 'considéré comme une clé en double de N'C' en utilisant le classement Latin1_General_CI_AS


11

J'ai une table avec une clé unique qui comprend une NVARCHAR(50)colonne (correcte ou non, mais est là). Ainsi, lorsque vous essayez d'insérer Școu C(peu importe l'ordre de l'insert), il se casse sur le 2ème insert en raison de problèmes de classement. Voici l'erreur:

(1 ligne (s) affectée (s)) Msg 2601, niveau 14, état 1, ligne 16 Impossible d'insérer une ligne de clé en double dans l'objet 'dbo.testT' avec l'index unique 'IX_TestT'. La valeur de clé en double est (C).

Sélectionnez les retours:

entrez la description de l'image ici

Le classement par défaut de la base de données est Latin1_General_CI_AS. J'ai passé du temps à chercher comment le résoudre, sans trop modifier la structure déjà existante, mais je ne trouve pas de moyen de travailler. J'ai essayé différentes collations et combinaisons, tout échoue. Lisez ( ici et ici ) sur les extensions de personnages et ainsi de suite, toujours coincé. Voici un exemple de code que j'utilise pour répliquer le problème, n'hésitez pas à modifier et à recommander tout ce qui pourrait aider à résoudre ce problème.

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;

Réponses:


10

Le problème est que les anciens classements SQL Server (c'est-à-dire ceux dont le nom commence par SQL_) et les deux premières versions des classements Windows (la 80série fournie avec SQL Server 2000 et qui n'ont pas de numéro de version dans le nom et la 90série qui fourni avec SQL Server 2005) n'ont pas les poids de tri pour un grand nombre de caractères. Cela a été principalement corrigé à partir de la 100série Collations fournie avec SQL Server 2008.

Comme vous pouvez le voir dans les exemples ci-dessous, le Șcaractère correspond à une chaîne vide lors de l'utilisation de classements non binaires, de version 80 ou 90 (et de SQL Server) car ils ont tous deux le même poids de tri: 0. Rien. Nada. Cela signifie que lorsque vous comparez N'Șc'avec N'C'(en utilisant les classements de pré-série 100), vous comparez vraiment N'c'avec 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)

Donc, malheureusement, vous devrez supprimer le PK, modifier la colonne pour avoir un classement à 100 niveaux (par exemple Latin1_General_100_CI_AS_SC), puis recréer le PK. Veuillez noter que la différence entre le classement suggéré et le classement actuel est à la fois le 100 et le _SCà la fin, ce qui lui permet de gérer correctement les caractères supplémentaires.

Cela ne signifie pas que vous devez:

  1. changer les classements des autres tables (sauf s'ils ont la même configuration que NVARCHARdans le PK)
  2. modifier le classement par défaut de la base de données. Le principal problème lié à la non-modification du classement de la base de données est qu'il y aura une différence de comportement entre faire table.column = N'Ș'et @variable = N'Ș'puisque les variables et les littéraux de chaîne utilisent le classement par défaut de la base de données.

Pour plus d'exemples de ce comportement, veuillez consulter la section "Caractères supplémentaires" de mon article de blog suivant:

L'Uni-Code: la recherche de la vraie liste de caractères valides pour les identificateurs T-SQL, partie 3 de 2 (identificateurs délimités)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.