2010-10-15 14 views
9

Si guardo deliberadamente espacios finales en una columna VARCHAR, ¿cómo puedo forzar a SQL Server a ver los datos como desajustados?¿Cómo puedo hacer que SQL Server devuelva FALSE para comparar varchars con y sin espacios finales?

SELECT 'foo' WHERE 'bar' = 'bar ' 

que he intentado:

SELECT 'foo' WHERE LEN('bar') = LEN('bar ') 

Un método que he visto flotando es anexar un carácter específico al final de cada cuerda y luego tira hacia atrás para una mi presentación ... pero esto parece bastante tonto.

¿Hay algún método que haya pasado por alto?

me he dado cuenta de que no se aplica a líder espacios así que quizás me quedo una función que invierte el orden de los caracteres antes de la comparación .... problema es que esto hace que la consulta unSARGable ....

+0

¿Comparar longitud también? – SteveCav

+1

Como dije, comparo la duración con los mismos resultados. – Matthew

+0

Me encontré con eso el otro día y lo único que pude encontrar fue el apéndice de la cuerda también. –

Respuesta

6

SQL Server los ve de manera diferente.

LEN (Transact-SQL)
Returns the number of characters of the specified string expression, excluding trailing blanks.
To return the number of bytes used to represent an expression, use the DATALENGTH function

También es mejor que ser conscientes de que SQL Server follows ANSI/ISO SQL-92 padding the character strings used in comparisons para que su partido longitudes antes de compararlos.

Actualización (posterior):
Eliminé mi código usando LIKE (que no rellena espacios durante la comparación) y DATALENGTH() ya que no hay interacción entre las cadenas.

De todos modos, esta pregunta es un duplicado de algunas anteriores en SO, que contiene respuestas, por ejemplo, this one. Y hay otros (no los leí para respuestas emocionantes) this, this, y otros. La búsqueda encuentra docenas en SO y trillones en internet. No sé cómo fue posible perder la respuesta.

+0

Creo que 'DATALENGTH' me funcionará bien aquí, o almacenará un' DATALENGTH' calculado en una columna para hacerlo más rápido a expensas de un byte. – Matthew

3

Como dijo, no creo que haya muchas opciones. Los únicos dos que podría subir con fueron los siguientes:

DECLARE @x nvarchar(50) 
DECLARE @y nvarchar(50) 
SET @x = 'CAT  ' 
SET @y = 'CAT' 

SELECT 1 WHERE len(@x + '_') = len(@y + '_') 

SELECT 1 WHERE reverse(@x) = reverse(@y) 

EDITAR

pensamiento de una tercera:

SELECT 1 WHERE REPLACE(@x, ' ', '_') = REPLACE(@y, ' ', '_') 

Y un cuarto, asumiendo que usted está en SQL 2005 +

SELECT 1 WHERE QUOTENAME(@x) = QUOTENAME(@y) 

Personalmente, me gusta el reverse idea the be st, pero todo depende de cuál funcione mejor para ti.

+0

+1 para el REVERSO, pero el LEN (foo + algo de char) es probable que sea el más eficiente! –

+0

@ p.campbell - interesante, ¡gracias por señalar eso! – LittleBobbyTables

+1

Todos ellos absorben la velocidad. Simplemente no hay una buena solución. – TomTom

1

Solo tengo dos sugerencias. Una sería volver a visitar el diseño que requiere que almacene espacios al final: siempre son difíciles de manejar en SQL.

El segundo (dados sus comentarios SARG-able) sería agregar una columna asignada a la tabla que almacena la longitud, y agregar esta columna a los índices apropiados. De esa manera, al menos, la comparación de longitud debe ser SARG-able.

+0

Esta pregunta debería haber sido cerrada como una estafa. Ya se había respondido de forma exhaustiva y repetida en SO, incluido el diseño (truncar espacios finales), que había dado en mi actualización, http://stackoverflow.com/questions/1146280/is-it-good-practice-to-trim-whitespace -leading-and-hanging-when-selecting-inse –

+1

@ vgv8 - Creo que este es sutilmente diferente, en el sentido de que el OP parece estar diciendo que tienen que almacenar el espacio en blanco final, y que es significativo. –

2

podría intentar somethign así:

declare @a varchar(10), @b varchar(10) 
set @a='foo' 
set @b='foo ' 

select @a, @b, DATALENGTH(@a), DATALENGTH(@b) 
+1

Sí. 'SELECT * FROM YourTable DONDE col = @searchterm y DATALENGTH (col) = DATALENGTH (@searchterm)' debe ser razonablemente sargable. –

+0

eso es genial Martin, estaba tratando de pensar en una forma de hacerlo. – DForck42

1

Después de una cierta búsqueda de la solución más sencilla que encontré fue en Anthony Bloesch WebLog.

Sólo añadir un texto (un char es suficiente) hasta el final de los datos (anexar)

SELECT 'foo' WHERE 'bar' + 'BOGUS_TXT' = 'bar ' + 'BOGUS_TXT' 

también trabaja para 'EN DONDE'

SELECT <columnA> 
FROM <tableA> 
WHERE <columnA> + 'BOGUS_TXT' in (SELECT <columnB> + 'BOGUS_TXT' FROM <tableB>) 
0

El enfoque de planeo usar es usar una comparación normal que debe ser indexable ("sargable") complementada por un DATALENGTH (porque LEN ignora el espacio en blanco). Se vería así:

DECLARE @testValue VARCHAR(MAX) = 'x'; 

SELECT t.Id, t.Value 
FROM dbo.MyTable t 
WHERE 1=1 
AND (t.Value = @testValue AND DATALENGTH(t.Value) = DATALENGTH(@testValue)) 

Es hasta el optimizador de consultas para decidir el orden de los filtros, pero debe optar por utilizar un índice para la búsqueda de datos si eso tiene sentido para la tabla que se está probando y luego filtrar aún más el resultado restante por la longitud con las operaciones escalares más costosas. Sin embargo, como se indicó en otra respuesta, sería mejor evitar estas operaciones escalares mediante el uso de una columna calculada e indexada. El método presentado aquí podría tener sentido si no tiene control sobre el esquema o si desea evitar el trabajo/complicación de configurar las columnas calculadas se considera más costoso que tener un peor rendimiento.

Cuestiones relacionadas