2011-06-20 10 views
5

Mam tabeli tak:Tabela Normalizacja (Parse oddzielonych przecinkami pól na poszczególne rekordy)

Device

DeviceId Parts 

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

Chciałbym utworzyć tabelę „części”, eksport danych z części kolumna do nowej tabeli. Będę upuść kolumnę Części po tym

oczekiwany wynik

Części

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 

Mogę to zrobić w SQL Server 2008 bez użycia kursorów?

+0

Co próbowałeś do tej pory. Podpowiedź wszystko, czego potrzebujesz tutaj, to tabela z partID (Int, Tożsamość (1,1)), partname i wstaw do tego z wyborem odrębnym. Po tym, że jeden Join dostanie ci drugi stół .. – Ash

+0

Próbowałem do tej pory kursorów, ale nie podoba mi się rozwiązanie i mam wrażenie, że powinien być lepszy sposób na zrobienie tego. –

Odpowiedz

5

- Konfiguracja:

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 

- Wynik:

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

Spójrz na użycie fn_Split, aby utworzyć zmienną tabeli z wartości rozdzielanych przecinkami. Możesz użyć tego do napędu wkładki.

EDYCJA: Właściwie, myślę, że nadal możesz potrzebować kursora. Pozostawiając tę ​​odpowiedź incase pomaga fn_Split.

+0

Lordy, proszę nie używać tej funkcji. Używa pętli mTVF i WHILE. To jeden z najwolniejszych dostępnych splitterów. –

0

Jeśli istnieje maksymalna liczba części na urządzenie, to tak, można to zrobić bez kursora, ale jest to dość skomplikowane.

Zasadniczo utwórz tabelę (lub widok lub podzapytanie), która ma identyfikator DeviceID i jedną PartID dla każdego możliwego indeksu w łańcuchu PartID. Można to osiągnąć, tworząc kolumny kolumn PartID, używając fn_split lub innej wybranej metody. Stamtąd robisz wiele samo-UNION tej tabeli, z jedną tabelą w self-UNION dla każdej kolumny PartID. Każda tabela w self-UNION ma tylko jedną z kolumn PartID zawartą na liście wyboru zapytania dla tabeli.

1

Będziesz potrzebował tabeli Tally, aby wykonać to bez kursora.

Postępuj zgodnie z instrukcjami, aby utworzyć tabelę sygnalizacyjną tutaj: Tally Tables by Jeff Moden

Ten skrypt umieścić tabelę w bazie danych Temp, więc prawdopodobnie chcesz zmienić „Zastosowanie DB” oświadczenie

Następnie można uruchomić poniższy skrypt, aby wstawić zestawienie urządzeń i części do tabeli tymczasowej. Następnie powinieneś być w stanie dołączyć do swojej tabeli części według nazwy części (aby uzyskać identyfikator) i wstawić ją do nowej tabeli 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) = ', ' 
Powiązane problemy