DONDE es igual a la condición devuelve resultados Unicode (ancho compl

DONDE es igual a la condición devuelve resultados Unicode (ancho completo) mapeados

Estamos consultando una base de datos de SQL Server para los nombres que están almacenados en una columna nvarchar. En esta tabla, tenemos dos valores que están en conflicto entre sí. Word y Word. El primero está hecho con letras latinas de ancho completo.

Cuando tratamos de seleccionar el nombre ASCII, también regresa la versión Unicode. Esto provoca conflictos ya que la consulta solo debería poder devolver una fila. A continuación se muestra una consulta que se puede utilizar para reproducir los resultados:

SELECT CASE WHEN N'Word' = N'Word' THEN 1 ELSE 0 END;

Esta consulta devuelve 1, mientras que esperamos que devuelva 0. Parece que SQL Server asigna versiones basadas en Unicode de cada letra a su variante ASCII.

¿Hay alguna forma de desactivar esta asignación entre los caracteres ASCII y Unicode? Sin dejar de ser capaz de ignorar las mayúsculas.

Mostrar la mejor respuesta

Necesitas usar COLLATION.

Siga mis ejemplos y descubra qué colación es adecuada para usted

Esta colación devuelve 1

SELECT CASE WHEN N'Word' COLLATE Latin1_General_CI_AS = N'Word' COLLATE Latin1_General_CI_AS THEN 1 ELSE 0 END 

Esta intercalación devuelve 0

SELECT CASE WHEN N'Word' COLLATE SQL_Latin1_General_Cp437_BIN = N'Word' COLLATE SQL_Latin1_General_Cp437_BIN THEN 1 ELSE 0 END  

El especificador de intercalación le dice a SQL Server cómo comparar caracteres.

Encuentre más detalles aquí

Lista de intercalaciones

Debido a que puede tener más variedad en sus datos, no puedo decirle qué intercalación es mejor para usted.

¡Gracias! La segunda intercalación SQL_Latin1_General_Cp437_BIN. Funciona en el caso de Unicode y ASCII. Pero también devolverá 0 en word == WORD. ¿Hay otro que no coincida con Unicode pero que aún coincida con diferentes mayúsculas?

Puede encontrar más información en los enlaces que acabo de agregar a mi respuesta

Cuando intentamos seleccionar el nombre ASCII, también regresa la versión Unicode.

Esta declaración es un malentendido sobre cómo funcionan las codificaciones. ASCII es una codificación de 8 bits y un conjunto de caracteres. Tiene valores de 0 a 127 y es común en la mayoría de las páginas de códigos y Unicode. Sin embargo, en realidad solo se aplica a los datos de VARCHAR. Al usar NVARCHAR, todos los caracteres son Unicode, incluso si esos caracteres se encuentran en otros juegos de caracteres. Así que aquí, solo se devuelven caracteres Unicode ya que NVARCHAR solo contiene caracteres Unicode (codificados como UTF-16 Little Endian). Da la casualidad de que el conjunto de caracteres ASCII se duplicó como un subconjunto de Unicode.

Es decir, lo que realmente estás diciendo aquí es que solo quieres los caracteres latinos regulares, no la versión de ancho completo.

Parece que SQL Server asigna versiones basadas en Unicode de cada letra a su variante ASCII.

Sí y no. Windows y SQL Server pueden asignar caracteres Unicode a caracteres de apariencia similar dentro de una página de códigos de 8 bits, pero eso solo ocurre cuando se convierte una cadena Unicode en una página de códigos de 8 bits (o de una página de códigos a otra). otro). Eso no está pasando aquí. Aquí, nuevamente, solo está tratando con Unicode. Da la casualidad de que las formas regulares y de ancho completo del alfabeto inglés de EE. UU. se consideran iguales cuando la intercalación es sensible al ancho In. Y según su pregunta y el caso de prueba (dos cosas separadas, ya que la intercalación de una columna se usa cuando se consulta una columna, pero la intercalación predeterminada de la base de datos se usa cuando se trata solo de literales de cadena y/o variables), está claro que las intercalaciones que usted están usando (que podrían ser la misma intercalación) son anchos insensibles.

Para solucionar esto, no utilice una intercalación binaria. El uso de una intercalación binaria es la respuesta de acceso desafortunada y comúnmente aceptada para corregir consultas cuando las personas obtienen más coincidencias de las que esperaban. Y a veces es la respuesta correcta, pero la mayoría de las veces, como con esta pregunta, no lo es.

Simplemente necesita agregar "sensibilidad de ancho" a la intercalación que está utilizando. Puede encontrar la intercalación de la columna con la siguiente consulta, simplemente complete el nombre de la tabla y el nombre de la columna correctos:

SELECT col.[collation_name]
FROM   sys.columns col
WHERE  col.[object_id] = OBJECT_ID(N'<schema_name>.<table_name>')
AND    col.[name] = N'<column_name>';

Si la Intercalación es una Intercalación de Windows (es decir, el nombre no comienza con SQL_), entonces podría agregar _WS a la final del nombre de la colación. Por ejemplo:

Latin1_General_100_CS_AS --> Latin1_General_100_CS_AS_WS

Si la intercalación es una intercalación de SQL Server (es decir, el nombre comienza con SQL_), ninguno de ellos permite la sensibilidad al ancho y debe elegir una intercalación de Windows equivalente. Si la Intercalación es SQL_Latin1_General_CP1_*, intente lo mismo comenzando con Latin1_General_100_.

-- current Collation (no width sensitivity)
SELECT CASE WHEN N'Word' = N'Word' COLLATE Latin1_General_100_CI_AS THEN 1
            ELSE 0 END;
-- 1


-- add width sensitivity
SELECT CASE WHEN N'Word' = N'Word' COLLATE Latin1_General_100_CI_AS_WS THEN 1
            ELSE 0 END;
-- 0


-- confirm case INsensitivity
SELECT CASE WHEN N'WORD' = N'Word' COLLATE Latin1_General_100_CI_AS_WS THEN 1
            ELSE 0 END;
-- 1

Para obtener más detalles sobre por qué primero debe intentar obtener la sensibilidad correcta antes de usar una intercalación binaria, consulte la siguiente publicación mía:

No, las intercalaciones binarias no son Se distingue entre mayúsculas y minúsculas

¡Gran respuesta! ¿Existe algún riesgo de cambiar una intercalación de columnas de una intercalación sql a una intercalación de Windows? ¿Se pueden perder o deformar los datos?

@bladefist ¡Gracias! Y, el "tipo" de Intercalación no es el problema. Si está hablando de una columna NVARCHAR / NCHAR / NTEXT, entonces no puede haber ninguna pérdida de datos ya que Unicode es un conjunto de caracteres único que incluye todos caracteres. Si está hablando de VARCHAR / CHAR / TEXT, entonces la diferencia es solo si está cambiando las páginas de códigos, en cuyo caso existe la posibilidad de pérdida de datos si la nueva página de códigos no contiene todos los caracteres actualmente en los datos. Pero ese riesgo existe al pasar de cualquier Cotejo a cualquier otro, independientemente del tipo o versión, etc.

@bladefist Además, esa es una buena pregunta, pero realmente debería publicarse como una pregunta separada y no solo en un comentario. Publique (si no se ha preguntado antes) y pegue un enlace aquí y lo responderé. También tengo una serie de blogs de 2 partes sobre prácticamente ese tema, comenzando con: ¿Qué intercalación se usa para convertir NVARCHAR a VARCHAR en una condición WHERE? (Parte A de 2: “Pato”).