Ajuste automático de SQL Server del valor varchar en igual comparación pero no como comparación

13

Encontré un comportamiento interesante en SQL Server (observado en 2005 y 2012) hoy que esperaba que alguien pudiera explicarlo.

Una consulta que realiza una comparación usando =un campo NVARCHAR ignora el espacio final en la cadena (o recorta automáticamente el valor antes de la comparación) pero la misma consulta que usa el likeoperador no ignora el espacio. La clasificación utilizada es Latin1_General_CI_AS en 2012.

Considere este violín de SQL: http://sqlfiddle.com/#!6/72262/4

Tenga en cuenta que el likeoperador no devuelve un resultado para la cadena de espacio final, pero el =operador sí. ¿Por qué es esto?

Puntos de bonificación: no puedo replicar esto en un campo VARCHAR, habría pensado que un espacio se manejaría de la misma manera en ambos tipos de datos, ¿es esto cierto?

WT_W
fuente
Estaba buscando escribir una restricción de verificación de que se recortaba una cadena. Encontré una solución alternativa que es verificar eso MyString+'x' = ltrim(rtrim(MyString))+'x'como se sugiere en este blog
default.kramer

Respuestas:

15

Mi respuesta inicial sugirió que el indicador ANSI_PADDING establecido en OFF puede ser el culpable de la diferencia de comportamiento. Sin embargo, esto es incorrecto; Este indicador solo tiene un efecto en el almacenamiento, pero no en la comparación de igualdad.

La diferencia proviene de la implementación de Microsoft del estándar SQL . El estándar establece que cuando se verifica la igualdad, ambas cadenas izquierda y derecha del operador de igualdad deben ser rellenadas para tener la misma longitud . Esto explica los siguientes resultados:

insert into test_padding (varchar_clmn, nvarchar_clmn) values ('space ', 'nspace ')
go
-- equality for varchar column
select count(*) from test_padding where varchar_clmn = 'space' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space    ' --returns 1
-- equality for nvarchar column
select count(*) from test_padding where nvarchar_clmn = 'nspace' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace    ' --returns 1

El operador LIKE no rellena sus operandos. También se comporta de manera diferente para VARCHARy los NVARCHARtipos de columna :

-- likeness for varchar column
select count(*) from test_padding where varchar_clmn like 'space' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space    ' -- returns 0
-- likeness for nvarchar column
select count(*) from test_padding where nvarchar_clmn like 'nspace' -- returns 0
select count(*) from test_padding where nvarchar_clmn like 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn like 'nspace    ' -- returns 0

El comportamiento del operador LIKE para el tipo ASCII es específico de SQL Server; para el tipo Unicode es compatible con ANSI.

Ralf
fuente
4

SQL nació en una era en la que la mayoría de los lenguajes de procesamiento de datos usaban longitudes fijas para cada campo / variable. El relleno automático de los campos de texto con espacios adicionales también fue parte de esa imagen. Para alinearse con ese comportamiento, el tipo CHAR SQL original se definió explícitamente para su operador '=' para ignorar los espacios finales. (Si le resulta extraño, muéstreme un caso convincente en el que los espacios finales anexados a un texto tengan un significado comercial real real ).

Los tipos SQL CHAR han evolucionado en todo tipo de direcciones desde entonces, pero no es inconcebible que ciertos tipos de datos más modernos aún hayan heredado algunas características de sus predecesores históricos.

Erwin Smout
fuente
"muéstrame un caso convincente en el que los espacios finales anexados a un texto tengan un significado comercial real real": almacenar datos significativos de espacios en blanco, como ciertos resultados de consola sin procesar y fragmentos XML no seguros.
Dai
1

En la documentación de LIKE (Transact-SQL) , Microsoft escribe (el énfasis es mío):

Coincidencia de patrones usando LIKE

LIKE admite la coincidencia de patrones ASCII y la coincidencia de patrones Unicode. Cuando todos los argumentos ... son tipos de datos de caracteres ASCII, se realiza la coincidencia de patrones ASCII. Si alguno de los argumentos es del tipo de datos Unicode, todos los argumentos se convierten a Unicode y se realiza la coincidencia de patrones Unicode. Cuando usa datos Unicode ... con LIKE, los espacios en blanco finales son significativos; sin embargo, para datos no Unicode, los espacios en blanco finales no son significativos. Unicode LIKE es compatible con el estándar ISO. ASCII LIKE es compatible con versiones anteriores de SQL Server.

Michel de Ruiter
fuente