Чому ці символи рівні на 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 символи представляють один зрозумілий людині персонаж. Чому їх так багато на карті символів Unicode?

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

Якщо я знаю причину різниці, я можу знайти рішення для її вирішення. Дякую.

Відповіді:


28

Усі символьні дані в SQL Server асоціюються з зіставленням, яке визначає домен символів, який може зберігатися, а також правила, які використовуються для порівняння та сортування даних. Збірка застосовується як до даних Unicode, так і до даних Unicode.

SQL Server включає 3 широкі категорії зіставлень: двійкові, застарілі та Windows. Збірники у двійковій категорії ( _BINсуфікс) використовують основні кодові точки для порівняння, тому порівняння рівності повертаються не рівними, якщо кодові точки відрізняються незалежно від символу. Спадкові ( 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'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.