¿Por qué estos caracteres son todos iguales en SQL Server?

20

Simplemente no entiendo. Ver 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'

Basado en la relación transitiva , significa que SQL Server los considera a todos como el mismo personaje.

Sin embargo, en otros entornos, por ejemplo, C #, no son lo mismo.

Lo que me confunde es:

  1. Cómo funciona la comparación de cadenas en SQL Server
  2. Por qué la comparación no se comporta igual en una máquina y una plataforma, sino en entornos diferentes
  3. Estos 4 personajes representan un personaje entendible por los humanos. ¿Por qué son tan abundantes en el mapa de caracteres Unicode?

Por supuesto, esto resulta en problemas tremendos, porque estoy trabajando en una aplicación de procesamiento de texto y los datos provienen de casi todas partes y necesito normalizar el texto antes de procesarlo.

Si conozco el motivo de la diferencia, podría encontrar una solución para manejarlo. Gracias.

Saeed Neamati
fuente

Respuestas:

28

Todos los datos de caracteres en SQL Server están asociados con una clasificación, que determina el dominio de los caracteres que se pueden almacenar, así como las reglas utilizadas para comparar y ordenar datos. La clasificación se aplica tanto a los datos Unicode como a los no Unicode.

SQL Server incluye 3 categorías amplias de intercalaciones: binario, heredado y Windows. Las intercalaciones en la categoría binaria ( _BINsufijo) utilizan los puntos de código subyacentes para comparar, por lo que las comparaciones de igualdad devuelven no iguales si los puntos de código difieren independientemente del carácter. Las SQL_clasificaciones heredadas ( prefijo) y de Windows proporcionan semántica de clasificación y comparación para las reglas de diccionario más naturales. Esto permite que las comparaciones consideren mayúsculas, acentos, ancho y Kana. Las intercalaciones de Windows proporcionan word-sortreglas más sólidas que se alinean estrechamente con el sistema operativo Windows, mientras que las intercalaciones heredadas solo consideran caracteres únicos.

El siguiente ejemplo ilustra las diferencias entre Windows y la intercalación binaria con el carácter 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;

En http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode se describen las razones por las cuales Unicode puede contener diferentes puntos de código para glifos idénticos . En resumen, puede ser por compatibilidad heredada o los caracteres no son canónicamente equivalentes. Tenga en cuenta que el carácter Teth se usa en diferentes idiomas ( http://en.wikipedia.org/wiki/Teth ).

Dan Guzman
fuente
15

Esto tiene algo que ver con la COLLATIONde su base de datos ( más información en BOL ).

No estoy completamente seguro del idioma del carácter específico con el que tiene un problema (supongo que persa basado en este hilo), pero si especifica la clasificación correcta en el operador de igualdad, obtendrá 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
fuente