2011-06-20 11 views
5

He (Parse coma campos en los registros individuales separados) una tabla como esta:Tabla Normalización

Dispositivo

DeviceId Parts 

1   Part1, Part2, Part3 
2   Part2, Part3, Part4 
3   Part1 

me gustaría crear una tabla de 'partes', exportar datos a partir de piezas columna a la nueva tabla. Voy a dejar la columna de piezas después de eso Resultado esperado

piezas

PartId PartName 

    1  Part1 
    2  Part2 
    3  Part3 
    4  Part4 

DevicePart

DeviceId PartId 

    1  1 
    1  2 
    1  3 
    2  2 
    2  3 
    2  4 
    3  1 

¿Puedo hacer esto en SQL Server 2008 sin utilizar los cursores?

+0

Qué has necesitado hasta ahora. Una sugerencia que todo lo que necesita aquí es una tabla con partID (Int, Identity (1,1)), nombre de parte e inserte en eso con una selección distinct..Después de eso, Join obtendrá la segunda tabla ... – Ash

+0

He probado los cursores hasta el momento, pero no me gusta la solución y creo que debería haber una mejor manera de hacerlo. –

Respuesta

5

- Configuración:

declare @Device table(DeviceId int primary key, Parts varchar(1000)) 
declare @Part table(PartId int identity(1,1) primary key, PartName varchar(100)) 
declare @DevicePart table(DeviceId int, PartId int) 

insert @Device 
values 
    (1, 'Part1, Part2, Part3'), 
    (2, 'Part2, Part3, Part4'), 
    (3, 'Part1') 

--script:

declare @DevicePartTemp table(DeviceId int, PartName varchar(100)) 

insert @DevicePartTemp 
select DeviceId, ltrim(x.value('.', 'varchar(100)')) 
from 
(
    select DeviceId, cast('<x>' + replace(Parts, ',', '</x><x>') + '</x>' as xml) XmlColumn 
    from @Device 
)tt 
cross apply 
    XmlColumn.nodes('x') as Nodes(x) 


insert @Part 
select distinct PartName 
from @DevicePartTemp 

insert @DevicePart 
select tmp.DeviceId, prt.PartId 
from @DevicePartTemp tmp 
    join @Part prt on 
     prt.PartName = tmp.PartName 

- Resultado:

select * 
from @Part 

PartId  PartName 
----------- --------- 
1   Part1 
2   Part2 
3   Part3 
4   Part4 


select * 
from @DevicePart 

DeviceId PartId 
----------- ----------- 
1   1 
1   2 
1   3 
2   2 
2   3 
2   4 
3   1 
0

Eche un vistazo al uso de fn_Split para crear una variable de tabla a partir de valores separados por comas. Puede usar esto para conducir su inserción.

EDITAR: En realidad, creo que aún puede necesitar un cursor. Dejando esta respuesta en caso de que fn_Split ayude.

+0

Lordy, por favor no use ESA función. Utiliza un bucle mTVF y WHILE. Es uno de los divisores más lentos disponibles. –

0

Si hay un número máximo de piezas por dispositivo, sí, se puede hacer sin un cursor, pero esto es bastante complejo.

Básicamente, cree una tabla (o vista o subconsulta) que tenga un DeviceID y una columna PartID para cada índice posible en la cadena PartID. Esto se puede lograr haciendo que las columnas PartID calculen columnas usando fn_split u otro método de su elección. A partir de allí, realiza una autounión múltiple de esta tabla, con una tabla en el auto-UNION para cada columna PartID. Cada tabla en el self-UNION tiene solo una de las columnas PartID incluidas en la lista de selección de la consulta para la tabla.

1

Necesitará una tabla Tally para lograr esto sin un cursor.

Siga las instrucciones para crear una tabla de conteo aquí: Tally Tables by Jeff Moden

Este script va a poner la tabla en la base de datos de temperatura, por lo que es probable que desee cambiar la declaración "Uso DB"

continuación, puede ejecutar el script a continuación para insertar un desglose de Dispositivos y Partes en una tabla temporal. Debería poder unirse a su tabla de partes por el nombre de la parte (para obtener la ID) e insertarla en su nueva tabla DevicePart.

select *, 
--substring(d.parts, 1, t.n) 
substring(d.parts, t.n, charindex(', ', d.parts + ', ',t.n) - t.n) 'Part' 
into #devicesparts 
from device d 
cross join tally t 
where t.n < (select max(len(parts))+ 1 from device) 
and substring(', ' + d.parts, t.n, 1) = ', ' 
Cuestiones relacionadas