Dlaczego te znaki są takie same w SQL Server?

20

Po prostu tego nie rozumiem. Zobacz to zapytanie 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'

W oparciu o relację przechodnią oznacza to, że SQL Server uważa, że ​​wszystkie mają ten sam znak.

Jednak w innych środowiskach, na przykład C #, nie są one takie same.

Jestem zdezorientowany:

  1. Jak działa porównanie ciągów w SQL Server
  2. Dlaczego porównanie nie zachowuje się tak samo na jednej maszynie i jednej platformie, ale w różnych środowiskach
  3. Te 4 znaki reprezentują jedną postać zrozumiałą dla człowieka. Dlaczego są tak obfite w mapę znaków Unicode?

To oczywiście powoduje ogromne problemy, ponieważ pracuję nad aplikacją do przetwarzania tekstu, a dane pochodzą niemal z każdego miejsca i muszę je znormalizować przed przetworzeniem.

Jeśli znam przyczynę różnicy, mogę znaleźć rozwiązanie, aby sobie z tym poradzić. Dziękuję Ci.

Saeed Neamati
źródło

Odpowiedzi:

28

Wszystkie dane znaków w SQL Server są powiązane z sortowaniem, które określa domenę znaków, które mogą być przechowywane, a także zasady stosowane do porównywania i sortowania danych. Sortowanie dotyczy zarówno danych Unicode, jak i innych niż Unicode.

SQL Server obejmuje 3 szerokie kategorie zestawień: binarne, starsze i Windows. Zestawienia w kategorii binarnej ( _BINsufiks) wykorzystują bazowe punkty kodowe do porównania, więc porównania równości zwracają nierówne, jeśli punkty kodowe różnią się niezależnie od znaku. Starsze ( SQL_przedrostek) i sortowanie w systemie Windows zapewniają semantykę sortowania i porównywania dla bardziej naturalnych reguł słownika. Pozwala to na porównania uwzględniające wielkość liter, akcenty, szerokość i Kana. Sortowania w systemie Windows zapewniają bardziej niezawodne word-sortreguły, które są ściśle dopasowane do systemu operacyjnego Windows, podczas gdy starsze zestawienia uwzględniają tylko pojedyncze znaki.

Poniższy przykład ilustruje różnice między systemem Windows a zestawieniem binarnym ze znakiem 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;

Powody, dla których Unicode może zawierać różne punkty kodowe dla identycznych glifów, zostały przedstawione w http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode . Podsumowując, może to być zgodność ze starszymi wersjami lub znaki nie są kanonicznie równoważne. Zauważ, że znak Teth jest używany w różnych językach ( http://en.wikipedia.org/wiki/Teth ).

Dan Guzman
źródło
15

Ma to coś wspólnego z COLLATIONbazą danych ( więcej informacji w BOL ).

Nie jestem całkowicie pewien języka określonego znaku, z którym masz problem (domyślam się, że perski jest oparty na tym wątku), ale jeśli określisz poprawne układanie w operatorze równości, otrzymasz dokładne wyniki.

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
źródło