2010-02-05 34 views
5

Tengo una columna Dirección en una tabla que necesito dividir en varias columnas en una vista en SQL Server 2005. Necesito dividir la columna en el carácter de fuente de línea, chr (10), y podría haber de 1 a 4 líneas (0 a 3 alimentaciones de línea) en la columna. A continuación hay un par de ejemplos de lo que debo hacer. ¿Cuál es la forma más simple de hacer que esto suceda?Columna Dirección dividida en columnas separadas en la vista SQL

Examples: 

Address     Address1  Address2  Address3   Address4 
------------  = ----------- ----------- ----------------- --------- 
My Company    My Company  123 Main St. Somewhere,NY 12345 
123 Main St.   
Somewhere,NY 12345 

Address     Address1  Address2  Address3  Address4 
------------  = ------------ ---------- ----------- --------- 
123 Main St.   123 Main St. 
+0

¿Hay alguna posibilidad de que los datos * no * estén almacenados en una sola columna? –

+0

Todas las líneas de direcciones se almacenan en una sola columna. – Jamie

Respuesta

3

esto dividirá la dirección utilizando la función ParseName y combinando eso con se unen para captar la información correcta en la columna correcta

si tiene más de 4 líneas de este método no funcionará

de edición: añadido el código para invertir el orden

create table #test (address varchar(1000)) 

    --test data 
    insert #test values('My Company 
    123 Main St.   
    Somewhere,NY 12345') 

    insert #test values('My Company2 
    666 Main St. 
    Bla Bla  
    Somewhere,NY 12345') 

    insert #test values('My Company2') 

    --split happens here 
          select 
replace(parsename(address,ParseLen +1),'^','') as Address1, 
replace(parsename(address,ParseLen),'^','') as Address2, 
replace(parsename(address,ParseLen -1),'^','') as Address3, 
replace(parsename(address,ParseLen -2),'^','') as Address4 
from(
select case ascii(right(address,1)) when 10 then 
replace(replace(left(address,(len(address)-1)),'.','^'),char(10),'.') 
else 
replace(replace(address,'.','^'),char(10),'.') end as address, 
case ascii(right(address,1)) when 10 then 
len(replace(replace(address,'.','^'),char(10),'.')) - 
len(replace(replace(address,'.','^'),char(10),'')) -1 
else 
len(replace(replace(address,'.','^'),char(10),'.')) - 
len(replace(replace(address,'.','^'),char(10),'')) end as ParseLen 
from #test) x 
+0

Hace un buen trabajo al analizar las piezas, pero la función parsename llena su matriz en orden inverso. Entonces, si tiene algo como 123.456.789, devuelve 1 = 789, 2 = 456 y 3 = 123. Y si tiene 123.456, devuelve 1 = 456 y 2 = 123. En ambos casos, necesito 1 = 123, 2 = 456 y en el primer ejemplo 3 = 789. No estoy seguro si eso está claro. Siento que debería ser capaz de hacer esto usando su método coalescente e ir en orden inverso o algo así, pero parece que no puedo hacerlo bien. – Jamie

+0

agregó el código para invertir el orden – SQLMenace

+0

Ok, ya casi está allí. El único problema que veo ahora es que devuelve NULL para los cuatro campos si hay un salto de línea al final del campo fuente. En otras palabras, hay una última línea en blanco. ¿Hay alguna forma de que podamos limpiar los canales de línea y/o espacios al final que puedan estar arrojándolos? Gracias por toda su ayuda SQLMenace! – Jamie

0

El texto de análisis en SQL no es divertido. Si tuviera que hacer algo como esto, exportaría la columna a un archivo de texto csv y lo analizaría en un lenguaje de scripting como Perl/PHP/Python. De esa forma puedo aprovechar las funciones de cadena integradas y la expresión regular del lenguaje de scripting.

1

Esto es muy desagradable ... os recomiendo que si quieres tratar a cada línea de dirección por separado, que se almacenan correctamente en el primer lugar. En lugar de seguir haciendo lo que está haciendo, agregue las columnas adicionales, corrija los datos existentes una vez (en lugar de "solucionarlos" cada vez que ejecute una consulta), y luego ajuste el procedimiento almacenado que realiza la inserción/actualización para que sepa usar las otras columnas.

DECLARE @Address TABLE(id INT IDENTITY(1,1), ad VARCHAR(MAX)); 

INSERT @Address(ad) SELECT 'line 1 
line 2 
line 3 
line 4' 
UNION ALL SELECT 'row 1 
row 2 
row 3' 
UNION ALL SELECT 'address 1 
address 2' 
UNION ALL SELECT 'only 1 entry here' 
UNION ALL SELECT 'let us try 5 lines 
line 2 
line 3 
line 4 
line 5'; 

SELECT 
    id, 
    Line1 = REPLACE(REPLACE(COALESCE(Line1, ''), CHAR(10), ''), CHAR(13), ''), 
    Line2 = REPLACE(REPLACE(COALESCE(Line2, ''), CHAR(10), ''), CHAR(13), ''), 
    Line3 = REPLACE(REPLACE(COALESCE(SUBSTRING(Rest, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), Rest), 0), LEN(Rest))), ''), CHAR(10), ''), CHAR(13), ''), 
    Line4 = REPLACE(REPLACE(COALESCE(SUBSTRING(Rest, NULLIF(CHARINDEX(CHAR(10), Rest) + 1, 1), LEN(Rest)), ''), CHAR(10), ''), CHAR(13), '') 
FROM 

(
    SELECT 
     id, 
     ad, 
     Line1, 
     Line2 = SUBSTRING(Rest, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), Rest), 0), LEN(Rest))), 
     Rest = SUBSTRING(Rest, NULLIF(CHARINDEX(CHAR(10), Rest) + 1, 1), LEN(Rest)) 
    FROM 
    (
     SELECT 
      id, 
      ad, 
      Line1 = SUBSTRING(ad, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), ad), 0), LEN(ad))), 
      Rest = SUBSTRING(ad, NULLIF(CHARINDEX(CHAR(10), ad) + 1, 1), LEN(ad)) 
     FROM 
      @address 
    ) AS x 
) AS y 
ORDER BY id; 

ParseName() truco Denis' es mucho más ordenado, por supuesto, pero hay que tener mucho cuidado con el uso de un carácter de reemplazo que es realmente imposible de aparecer en los datos de forma natural. El quilate (^) es probablemente una buena apuesta, pero como dije, debes tener cuidado.

También hay paquetes de software que son realmente buenos para depurar direcciones y otros datos demográficos. Pero limpiar la entrada de datos es lo más importante que voy a seguir insistiendo ... si cada línea de direcciones debe tratarse por separado, entonces guárdelas de esa manera.

+0

Estoy totalmente de acuerdo al 100%, pero en este caso particular, no tengo control sobre la estructura de los datos. Es frustrante, pero es lo que es. – Jamie

+1

Bueno, mientras los usuarios estén dispuestos a esperar la vista para realizar esta división cada vez que ejecute una consulta ... entonces creo que tiene razón, es lo que es (diseño horrible). –

Cuestiones relacionadas