Me encontré con algo un poco extraño esta mañana y pensé en enviarlo para comentarios.
¿Alguien puede explicar por qué la siguiente consulta SQL imprime "igual" cuando se ejecuta contra SQL 2008. El nivel de compatibilidad de db se establece en 100.
if '' = ' '
print 'equal'
else
print 'not equal'
Y esto devuelve 0:
select (LEN(' '))
Parece estar recortando automáticamente el espacio. No tengo idea de si este era el caso en versiones anteriores de SQL Server, y ya no tengo ninguno para probarlo.
Me encontré con esto porque una consulta de producción devolvía resultados incorrectos. No puedo encontrar este comportamiento documentado en ninguna parte.
¿Alguien tiene alguna información sobre esto?
Respuestas:
varchar
sy la igualdad son espinosos en TSQL. LaLEN
función dice:Debe utilizar
DATALENGTH
para obtener unbyte
recuento real de los datos en cuestión. Si tiene datos Unicode, tenga en cuenta que el valor que obtenga en esta situación no será el mismo que la longitud del texto.print(DATALENGTH(' ')) --1 print(LEN(' ')) --0
Cuando se trata de igualdad de expresiones, las dos cadenas se comparan por igualdad de esta manera:
Es el paso intermedio el que está causando resultados inesperados; después de ese paso, está comparando de manera efectiva los espacios en blanco con los espacios en blanco, por lo que se considera que son iguales.
LIKE
se comporta mejor que=
en la situación de "espacios en blanco" porque no realiza relleno de espacios en blanco en el patrón que estaba tratando de hacer coincidir:Daré
eq
mientras:Daré
ne
Sin
LIKE
embargo, tenga cuidado con : no es simétrico: trata los espacios en blanco finales como significativos en el patrón (RHS) pero no en la expresión de coincidencia (LHS). Lo siguiente se toma de aquí :declare @Space nvarchar(10) declare @Space2 nvarchar(10) set @Space = '' set @Space2 = ' ' if @Space like @Space2 print '@Space Like @Space2' else print '@Space Not Like @Space2' if @Space2 like @Space print '@Space2 Like @Space' else print '@Space2 Not Like @Space' @Space Not Like @Space2 @Space2 Like @Space
fuente
sql-server-2008 r2
recibo,@Space Not Like @Space2 @Space2 Not Like @Space
. ¿Alguna idea de por qué?@Space Not Like @Space2 @Space2 Not Like @Space
El operador = es T-SQL no es tanto "igual" como "son la misma palabra / frase, de acuerdo con la intercalación del contexto de la expresión", y LEN es "el número de caracteres en la palabra / frase". Ninguna intercalación trata los espacios en blanco finales como parte de la palabra / frase que los precede (aunque sí tratan los espacios en blanco iniciales como parte de la cadena que preceden).
Si necesita distinguir 'esto' de 'esto', no debe usar el operador "son la misma palabra o frase" porque "esto" y "esto" son la misma palabra.
La idea de way = works es la idea de que el operador de igualdad de cadenas debe depender del contenido de sus argumentos y del contexto de intercalación de la expresión, pero no debe depender de los tipos de argumentos, si ambos son tipos de cadena .
El concepto de lenguaje natural de "estas son la misma palabra" no suele ser lo suficientemente preciso como para que pueda ser capturado por un operador matemático como =, y no existe el concepto de tipo de cadena en el lenguaje natural. El contexto (es decir, la colación) importa (y existe en el lenguaje natural) y es parte de la historia, y las propiedades adicionales (algunas que parecen extravagantes) son parte de la definición de = para que quede bien definido en el mundo antinatural de datos.
En el tema del tipo, no querrá que las palabras cambien cuando se almacenan en diferentes tipos de cadenas. Por ejemplo, los tipos VARCHAR (10), CHAR (10) y CHAR (3) pueden contener representaciones de la palabra 'gato' y? = 'gato' debería permitirnos decidir si un valor de cualquiera de estos tipos contiene la palabra 'gato' (con cuestiones de caso y acento determinados por la colación).
Respuesta al comentario de JohnFx:
Consulte Uso de datos char y varchar en Libros en pantalla. Citando de esa página, el énfasis es mío:
Estoy de acuerdo en que podría ser más fácil de encontrar, pero está documentado.
También vale la pena señalar que la semántica de SQL, donde = tiene que ver con los datos del mundo real y el contexto de la comparación (a diferencia de algo sobre los bits almacenados en la computadora) ha sido parte de SQL durante mucho tiempo. La premisa de RDBMS y SQL es la representación fiel de datos del mundo real, de ahí su soporte para las intercalaciones muchos años antes de que ideas similares (como CultureInfo) ingresaran al ámbito de los lenguajes tipo Algol. La premisa de esos lenguajes (al menos hasta hace muy poco) era la resolución de problemas en ingeniería, no la gestión de datos comerciales. (Recientemente, el uso de lenguajes similares en aplicaciones que no son de ingeniería, como la búsqueda, está haciendo algunos avances, pero Java, C #, etc. aún están luchando con sus raíces no comerciales).
En mi opinión, no es justo criticar a SQL por ser diferente de "la mayoría de los lenguajes de programación". SQL fue diseñado para admitir un marco para el modelado de datos comerciales que es muy diferente de la ingeniería, por lo que el lenguaje es diferente (y mejor para su objetivo).
Diablos, cuando se especificó SQL por primera vez, algunos lenguajes no tenían ningún tipo de cadena incorporado. Y en algunos idiomas aún, el operador igual entre cadenas no compara datos de caracteres en absoluto, ¡sino que compara referencias! No me sorprendería si en otra década o dos, la idea de que == depende de la cultura se convierta en la norma.
fuente
Encontré este artículo de blog que describe el comportamiento y explica por qué.
Más información también disponible en MSKB316626
fuente
Hace un tiempo hubo una pregunta similar en la que analicé un problema similar aquí
En lugar de
LEN(' ')
, useDATALENGTH(' ')
- eso le da el valor correcto.Las soluciones fueron usar una
LIKE
cláusula como se explica en mi respuesta allí, y / o incluir una segunda condición en laWHERE
cláusula para verificarDATALENGTH
también.Lea esa pregunta y los enlaces allí.
fuente
Para comparar un valor con un espacio literal, también puede utilizar esta técnica como alternativa a la declaración LIKE:
fuente
Cómo diferenciar registros en select con campos char / varchar en sql server: ejemplo:
declare @mayvar as varchar(10) set @mayvar = 'data ' select mykey, myfield from mytable where myfield = @mayvar
esperado
mykey (int) | myfield (varchar10)
1 | 'datos'
adquirido
mykey | Mi campo
1 | 'datos' 2 | 'datos'
incluso si escribo
select mykey, myfield from mytable where myfield = 'data'
(sin el espacio en blanco final) obtengo los mismos resultados.como lo resolví En este modo:
select mykey, myfield from mytable where myfield = @mayvar and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)
y si hay un índice en myfield, se usará en cada caso.
Espero que sea util.
fuente
Otra forma es volver a ponerlo en un estado en el que el espacio tiene valor. por ejemplo: reemplace el espacio con un carácter conocido como _
if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_') print 'equal' else print 'not equal'
devuelve: no es igual
No es ideal, y probablemente lento, pero es otra forma rápida de avanzar cuando se necesita rápidamente.
fuente
A veces uno tiene que lidiar con espacios en los datos, con o sin otros caracteres, aunque la idea de usar Null es mejor, pero no siempre se puede usar. Me encontré con la situación descrita y la resolví de esta manera:
Por supuesto, no haría eso para una gran cantidad de datos, pero funciona de forma rápida y sencilla para unas cien líneas ...
fuente