Función LEN que no incluye espacios finales en SQL Server

Tengo la siguiente tabla de prueba en SQL Server 2005:

CREATE TABLE [dbo].[TestTable] ( [ID] [int] NOT NULL, [TestField] [varchar](100) NOT NULL ) 

Poblado con:

 INSERT INTO TestTable (ID, TestField) VALUES (1, 'A value'); -- Len = 7 INSERT INTO TestTable (ID, TestField) VALUES (2, 'Another value '); -- Len = 13 + 6 spaces 

Cuando trato de encontrar la longitud de TestField con la función SQL Server LEN (), no cuenta los espacios finales, por ejemplo:

 -- Note: Also results the grid view of TestField do not show trailing spaces (SQL Server 2005). SELECT ID, TestField, LEN(TestField) As LenOfTestField, -- Does not include trailing spaces FROM TestTable 

¿Cómo incluyo los espacios finales en el resultado de la longitud?

Esto está claramente documentado por Microsoft en MSDN en http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspx , que indica que LEN “devuelve el número de caracteres de la expresión de cadena especificada, excluyendo espacios en blanco al final “. Sin embargo, es un detalle fácil de perder si no tienes cuidado.

En su lugar, debe usar la función DATALENGTH; consulte http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx , que “devuelve la cantidad de bytes utilizados para representar cualquier expresión”.

Ejemplo:

 SELECT ID, TestField, LEN(TestField) As LenOfTestField, -- Does not include trailing spaces DATALENGTH(TestField) As DataLengthOfTestField -- Shows the true length of data, including trailing spaces. FROM TestTable 

Puedes usar este truco:

LEN (Str + ‘x’) – 1

Yo uso este método:

 LEN(REPLACE(TestField, ' ', '.')) 

Prefiero esto sobre DATALENGTH porque esto funciona con diferentes tipos de datos, y prefiero que se agregue un carácter al final porque no tienes que preocuparte por el borde donde la cadena ya está en la longitud máxima.

Nota: probaría el rendimiento antes de usarlo contra un conjunto de datos muy grande; aunque lo probé contra filas de 2M y no fue más lento que LEN sin el REEMPLAZO …

“¿Cómo incluyo los espacios finales en el resultado de la longitud?”

Consigue que alguien archive una solicitud de mejora de SQL Server / informe de error porque casi todas las soluciones enumeradas para este problema increíblemente simple aquí tienen alguna deficiencia o son ineficientes. Esto todavía parece ser cierto en SQL Server 2012. La característica de recorte automático puede provenir de ANSI / ISO SQL-92, pero parece que hay algunos agujeros (o la falta de contarlos).

Por favor vote “Agregar configuración para que LEN cuente el espacio en blanco al final” aquí:

https://feedback.azure.com/forums/908035-sql-server/suggestions/34673914-add-setting-so-len-counts-trailing-whitespace

Enlace de conexión jubilada: https://connect.microsoft.com/SQLServer/feedback/details/801381

Hay problemas con las dos respuestas mejor votadas. La respuesta que recomienda DATALENGTH es propensa a errores del progtwigdor. El resultado de DATALENGTH debe dividir por el 2 para los tipos NVARCHAR , pero no para los tipos VARCHAR . Esto requiere conocimiento del tipo de longitud que está obteniendo, y si ese tipo cambia, debe cambiar diligentemente los lugares donde utilizó DATALENGTH .

También hay un problema con la respuesta más votada (que admito que era mi forma preferida de hacerlo hasta que este problema me mordió). Si la longitud de la que está obteniendo es de tipo NVARCHAR(4000) , y en realidad contiene una cadena de 4000 caracteres, SQL ignorará el carácter anexado en lugar de arrojar implícitamente el resultado a NVARCHAR(MAX) . El resultado final es una longitud incorrecta. Lo mismo sucederá con VARCHAR (8000).

Lo que he encontrado funciona, es casi tan rápido como el viejo LEN , es más rápido que LEN(@s + 'x') - 1 para cadenas grandes, y no asume que el ancho del carácter subyacente es el siguiente:

 DATALENGTH(@s) / DATALENGTH(LEFT(LEFT(@s, 1) + 'x', 1)) 

Esto obtiene la longitud de datos, y luego se divide por la longitud de datos de un solo carácter de la cadena. El apéndice de ‘x’ cubre el caso donde la cadena está vacía (lo que daría una división por cero en ese caso). Esto funciona si @s es VARCHAR o NVARCHAR . Al hacer la LEFT de 1 carácter antes del apéndice, se afeita un poco cuando la cuerda es grande. El problema con esto, sin embargo, es que no funciona correctamente con cadenas que contienen pares de sustitución.

Hay otra manera mencionada en un comentario a la respuesta aceptada, usando REPLACE(@s,' ','x') . Esa técnica da la respuesta correcta, pero es un par de órdenes de magnitud más lenta que las otras técnicas cuando la cuerda es grande.

Dados los problemas presentados por los pares de sustitución en cualquier técnica que use DATALENGTH , creo que el método más seguro que da las respuestas correctas que conozco es el siguiente:

 LEN(CONVERT(NVARCHAR(MAX), @s) + 'x') - 1 

Esto es más rápido que la técnica REPLACE , y mucho más rápido con cadenas más largas. Básicamente esta técnica es la técnica LEN(@s + 'x') - 1 , pero con protección para el caso de borde donde la cadena tiene una longitud de 4000 (para nvarchar) u 8000 (para varchar), de modo que la respuesta correcta es dado incluso por eso. También debe manejar cadenas con pares de sustitución correctamente.

También debe asegurarse de que sus datos se guarden realmente con los espacios en blanco finales. Cuando ANSI PADDING está desactivado (no predeterminado):

Se recortan los espacios en blanco al final en los valores de caracteres insertados en una columna varchar.

LEN corta los espacios finales por defecto, así que encontré esto funcionó cuando los movió al frente

(LEN (REVERSE (TestField))

Si quisieras, podrías decir

 SELECT t.TestField, LEN(REVERSE(t.TestField)) AS [Reverse], LEN(t.TestField) AS [Count] FROM TestTable t WHERE LEN(REVERSE(t.TestField)) <> LEN(t.TestField) 

No use esto para espacios principales, por supuesto.

Debe definir una función CLR que devuelva el campo Longitud de cadena, si no le gusta la concatenación de cadena. Uso LEN('x' + @string + 'x') - 2 en mis casos de uso de producción.

Si no le gusta el DATALENGTH debido a n / varchar, ¿qué le DATALENGTH :

 select DATALENGTH(@var)/isnull(nullif(DATALENGTH(left(@var,1)),0),1) 

que es solo

 select DATALENGTH(@var)/DATALENGTH(left(@var,1)) 

envuelto con protección de división por cero.

Al dividir por DATALENGTH de un único carácter, obtenemos la longitud normalizada.

(Por supuesto, sigue teniendo problemas con los pares de sustitución si eso es una preocupación).

use SELECT DATALENGTH (‘cadena’)