Pourquoi ces caractères sont tous égaux dans SQL Server?

20

Je ne comprends tout simplement pas. Voir cette requête SQL:

select nchar(65217) -- ﻁ
select nchar(65218) -- ﻂ
select nchar(65219) -- ﻃ
select nchar(65220) -- ﻄ
if nchar(65217) = nchar(65218)
    print 'equal'
if nchar(65217) = nchar(65219)
    print 'equal'
if nchar(65217) = nchar(65220)
    print 'equal'

Basé sur une relation transitive , cela signifie que SQL Server les considère tous comme le même caractère.

Cependant, dans d'autres environnements, disons par exemple C #, ils ne sont pas identiques.

Ce qui me déroute, c'est:

  1. Fonctionnement de la comparaison de chaînes dans SQL Server
  2. Pourquoi la comparaison ne se comporte pas de la même façon sur une machine et une plate-forme, mais dans des environnements différents
  3. Ces 4 personnages représentent un personnage compréhensible par l'homme. Pourquoi ils sont si abondants dans la carte de caractères Unicode?

Cela entraîne bien sûr d'énormes problèmes, car je travaille sur une application de traitement de texte et les données viennent presque de partout et j'ai besoin de normaliser le texte avant de le traiter.

Si je connais la raison de la différence, je pourrais trouver une solution pour y faire face. Je vous remercie.

Saeed Neamati
la source

Réponses:

28

Toutes les données de caractères dans SQL Server sont associées à un classement, qui détermine le domaine des caractères pouvant être stockés ainsi que les règles utilisées pour comparer et trier les données. Le classement s'applique aux données Unicode et non-Unicode.

SQL Server comprend 3 grandes catégories de classements: binaire, hérité et Windows. Les classements dans la catégorie binaire ( _BINsuffixe) utilisent les points de code sous-jacents pour comparer, de sorte que les comparaisons d'égalité retournent différentes si les points de code diffèrent quel que soit le caractère. Les SQL_classements hérités ( préfixe) et Windows fournissent une sémantique de tri et de comparaison pour les règles de dictionnaire les plus naturelles. Cela permet aux comparaisons de considérer la casse, les accents, la largeur et Kana. Les classements Windows fournissent des word-sortrègles plus robustes qui s'alignent étroitement avec le système d'exploitation Windows tandis que les classements hérités ne prennent en compte que des caractères uniques.

L'exemple ci-dessous illustre les différences entre Windows et le classement binaire avec le caractère Teth:

CREATE TABLE dbo.WindowsColationExample
    (
      Character1 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character2 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character3 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character4 nchar(1) COLLATE Arabic_100_CI_AS_SC
    );

CREATE TABLE dbo.BinaryColationExample
    (
      Character1 nchar(1) COLLATE Arabic_100_BIN
    , Character2 nchar(1) COLLATE Arabic_100_BIN
    , Character3 nchar(1) COLLATE Arabic_100_BIN
    , Character4 nchar(1) COLLATE Arabic_100_BIN
    );

INSERT  INTO dbo.BinaryColationExample
VALUES  ( NCHAR(65217), NCHAR(65218), NCHAR(65219), NCHAR(65220) );
INSERT  INTO dbo.WindowsColationExample
VALUES  ( NCHAR(65217), NCHAR(65218), NCHAR(65219), NCHAR(65220) );

--all characters compare not equal
SELECT *
FROM dbo.BinaryColationExample
WHERE
    character1 = character2
    OR character1 = character3
    OR character1 = character4
    OR character2 = character3
    OR character2 = character4
    OR character3 = character4;

--all characters compare equal
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character2;
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character3;
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character4;
SELECT *
FROM dbo.WindowsColationExample
WHERE character2 = character3;
SELECT *
FROM dbo.WindowsColationExample
WHERE character2 = character4;
SELECT *
FROM dbo.WindowsColationExample
WHERE character3 = character4;

Les raisons pour lesquelles Unicode peut contenir différents points de code pour des glyphes identiques sont décrites dans http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode . Je résume, cela peut être pour la compatibilité héritée ou les caractères ne sont pas équivalents canoniquement. Notez que le caractère Teth est utilisé dans différentes langues ( http://en.wikipedia.org/wiki/Teth ).

Dan Guzman
la source
15

Cela a quelque chose à voir avec le fonctionnement COLLATIONde votre base de données ( plus d'informations dans BOL ).

Je ne suis pas entièrement sûr de la langue du caractère spécifique avec lequel vous rencontrez un problème (je suppose que le persan est basé sur ce fil), mais si vous spécifiez le classement correct dans l'opérateur d'égalité, vous obtenez des résultats précis.

if nchar(65217) COLLATE Persian_100_BIN = nchar(65218) COLLATE Persian_100_BIN 
    print 'equal'; -- nothing returned
if nchar(65217)  COLLATE Persian_100_BIN  = nchar(65217)  COLLATE Persian_100_BIN 
    print 'equal'; -- prints 'equal'
if nchar(65217) COLLATE Latin1_General_CI_AI = nchar(65220) COLLATE Latin1_General_CI_AI
    print 'equal'; -- prints 'equal'
Mark Sinkinson
la source