Por que esses caracteres são todos iguais no SQL Server?

20

Eu simplesmente não entendo. Veja esta consulta 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'

Com base na relação transitiva , significa que o SQL Server considera todos eles com o mesmo caractere.

No entanto, em outros ambientes, por exemplo, C #, eles não são os mesmos.

O que me deixa confuso é:

  1. Como a comparação de cadeias funciona no SQL Server
  2. Por que a comparação não se comporta da mesma maneira em uma máquina e uma plataforma, mas em ambientes diferentes
  3. Esses 4 caracteres representam um caractere compreensível pelo homem. Por que eles são tão abundantes no mapa de caracteres Unicode?

Obviamente, isso resulta em tremendos problemas, porque estou trabalhando em um aplicativo de processamento de texto e os dados vêm quase de todos os lugares e preciso normalizar o texto antes de processá-lo.

Se eu souber o motivo da diferença, talvez encontre uma solução para lidar com isso. Obrigado.

Saeed Neamati
fonte

Respostas:

28

Todos os dados de caracteres no SQL Server estão associados a um agrupamento, que determina o domínio dos caracteres que podem ser armazenados, bem como as regras usadas para comparar e classificar dados. O agrupamento se aplica aos dados Unicode e Não Unicode.

O SQL Server inclui três grandes categorias de agrupamentos: binário, herdado e Windows. Agrupamentos na categoria binária ( _BINsufixo) usam os pontos de código subjacentes para comparar, para que as comparações de igualdade retornem diferentes se os pontos de código diferirem, independentemente do caractere. Os SQL_agrupamentos herdados ( prefixo) e Windows fornecem semântica de classificação e comparação para as regras de dicionário mais naturais. Isso permite que as comparações considerem maiúsculas e minúsculas, acentos, largura e Kana. Os agrupamentos do Windows fornecem word-sortregras mais robustas que se alinham ao sistema operacional Windows, enquanto os agrupamentos herdados consideram apenas caracteres únicos.

O exemplo abaixo ilustra as diferenças entre o Windows e o agrupamento binário com o caractere 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;

Os motivos pelos quais o Unicode pode conter pontos de código diferentes para glifos idênticos estão descritos em http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode . Resumindo, pode ser para compatibilidade herdada ou os caracteres não são canonicamente equivalentes. Observe que o caractere Teth é usado em diferentes idiomas ( http://en.wikipedia.org/wiki/Teth ).

Dan Guzman
fonte
15

Isso tem algo a ver com o COLLATIONdo seu banco de dados ( mais informações no BOL ).

Não tenho muita certeza do idioma do caractere específico com o qual você está tendo problemas (acho que persa com base nesse segmento), mas se você especificar o agrupamento correto no operador de igualdade, obterá resultados precisos.

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
fonte