Почему эти символы все равны в SQL Server?

20

Я просто не понимаю Посмотрите этот запрос 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'

Основанный на транзитивных отношениях , это означает, что SQL Server считает, что все они являются одним и тем же символом.

Однако в других средах, например, C #, они не одинаковы.

Что меня смущает, так это:

  1. Как работает сравнение строк в SQL Server
  2. Почему сравнение не ведет себя одинаково на одной машине и одной платформе, но в разных средах
  3. Эти 4 символа представляют одного понятного человеку символа. Почему их так много в символьной карте Юникода?

Это, конечно, приводит к огромным проблемам, потому что я работаю над приложением для обработки текста, и данные поступают почти отовсюду, и мне нужно нормализовать текст перед его обработкой.

Если я знаю причину различий, я мог бы найти решение, чтобы справиться с этим. Спасибо.

Саид Нямати
источник

Ответы:

28

Все символьные данные в SQL Server связаны с сопоставлением, которое определяет область символов, которые могут быть сохранены, а также правила, используемые для сравнения и сортировки данных. Сопоставление применяется как к данным Unicode, так и не Unicode.

SQL Server включает в себя 3 широкие категории параметров сортировки: двоичные, устаревшие и Windows. Для сравнения в двоичной категории ( _BINсуффиксе) используются базовые кодовые точки для сравнения, поэтому сравнения на равенство возвращают неравное значение, если кодовые точки различаются независимо от символа. Преобразования Legacy ( SQL_префикс) и Windows обеспечивают семантику сортировки и сравнения для более естественных правил словаря. Это позволяет при сравнении учитывать регистр, акценты, ширину и кана. Параметры сортировки Windows предоставляют более надежные word-sortправила, которые тесно связаны с ОС Windows, тогда как в устаревших параметрах сортировки учитываются только отдельные символы.

Пример ниже иллюстрирует различия между Windows и двоичным сопоставлением с символом 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;

Причины, по которым Unicode может содержать разные кодовые точки для одинаковых символов, описаны в http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode . Подводя итог, это может быть для унаследованной совместимости или символы не канонически эквивалентны. Обратите внимание, что символ Teth используется на разных языках ( http://en.wikipedia.org/wiki/Teth ).

Дэн Гусман
источник
15

Это как-то связано с COLLATIONвашей базой данных ( больше информации на BOL ).

Я не совсем уверен в языке конкретного символа, с которым у вас возникли проблемы (я предполагаю, что персидский язык основан на этой теме), но если вы укажете правильное сопоставление в операторе равенства, то вы получите точные результаты.

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'
Марк Синкинсон
источник