2010-09-20 15 views
5

Estoy generando sentencias T-SQL SELECT para tablas para las cuales no tengo información de tipo de datos por adelantado. En estas declaraciones, necesito realizar operaciones de manipulación de cadenas que dependen de la longitud del valor original de las columnas de las tablas.T-SQL: ¿Cómo obtener la longitud exacta de una cadena en caracteres?

Un ejemplo (pero no el único) es insertar un texto en una posición específica en una cadena, incluyendo la opción para insertarlo en el extremo:

SELECT 
    CASE WHEN (LEN ([t0].[Product] = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 

(el caso cuando + LEN es requerido porque STUFF no me permite insertar texto al final de una cadena.)

El problema es que LEN excluye los espacios en blanco finales, lo que arruinará el cálculo. Sé que puedo usar DATALENGTH, que no excluye los espacios en blanco finales, pero no puedo convertir los bytes devueltos por DATALENGTH a los caracteres requeridos por STUFF porque no sé si la columna Product es de tipo varchar o nvarchar.

Entonces, ¿cómo puedo generar una declaración SQL que depende de la longitud exacta de una cadena en caracteres sin información inicial sobre el tipo de datos de cadena que se utiliza?

Respuesta

12

Esto es lo que terminé usando:

SELECT 
    CASE WHEN ((LEN ([t0].[Product] + '#') - 1) = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 

Las mediciones indican que la LEN (. .. + '#') - 1 truco es aproximadamente la misma velocidad que LEN (...) solo.

¡Gracias por todas las buenas respuestas!

+0

+1 para una solución que funciona! –

+0

+1 Eso podría ser un truco útil. –

3

¿No puede buscar la información del tipo para las columnas en las tablas del sistema?

De lo contrario, para determinar si una columna es varchar o , esto lo haría.

create table #test 
(
c varchar(50), 
n nvarchar(50) 
) 

insert into #test values ('1,2,3,4 ',N'1,2,3,4,5  ') 

SELECT 
     CASE 
       WHEN datalength(CAST(c AS nvarchar(MAX))) = datalength(c) 
       THEN 'c is nvarchar' 
       ELSE 'c is char' 
     END, 
     CASE 
       WHEN datalength(CAST(n AS nvarchar(MAX))) = datalength(n) 
       THEN 'n is nvarchar' 
       ELSE 'n is char' 
     END 
FROM #test 
+0

Buscando la información: probablemente sea posible, pero difícil. Tampoco estoy seguro de cómo funcionaría esto. –

+0

La prueba también es interesante, pero creo que me gusta el REPLACE hackear un poco mejor con respecto a la "legibilidad" de la declaración resultante. –

+0

@Fabien: estoy bastante seguro de que buscar la información del tipo funcionará mejor que hacer un reemplazo en cada cadena de la columna o un molde en cada cadena. –

4

probar esto:

SELECT 
    CASE WHEN (LEN (REPLACE([t0].[Product],' ', '#') = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 
+0

Buena idea, debería haber tenido este yo ... –

+0

Esto es muy ineficiente, como lo muestran mis medidas. –

+1

Sin embargo, una rápida variación de esto es tan rápida como un rayo: LEN ([t0]. [Product] + '#') - 1 Esta es aproximadamente la misma velocidad que LEN ([t0]. [Product]) solo. .. –

1

Uso DATALENGTH y SQL_VARIANT_PROPERTY:

SELECT 
    CASE 
    WHEN 8 
     = DATALENGTH([t0].[Product]) 
    /CASE SQL_VARIANT_PROPERTY([t0].[Product],'BaseType') WHEN 'nvarchar' THEN 2 ELSE 1 END 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 
+0

He probado esto, y aunque se ve exactamente como lo que necesito, no funciona con varchar (max)/nvarchar (max) porque sql_variant no puede contener dichos valores. –

0

Si no hay espacios en blanco iniciales, len(reverse(column_name)) le dará la longitud de la columna.

Cuestiones relacionadas