2011-11-08 15 views
5

Jaki byłby właściwy sposób na przeanalizowanie poniższego bloku XML w tabeli SQL Server zgodnie z pożądanym układem (poniżej)? Czy można to zrobić za pomocą pojedynczej instrukcji SELECT, bez UNION lub pętli? Którzy chętni? Z góry dziękuję. XML wejściowe:Parsowanie zagnieżdżonego XML do tabeli SQL

<ObjectData> 
    <Parameter1>some value</Parameter1> 
    <Parameter2>other value</Parameter2> 
    <Dates> 
    <dateTime>2011-02-01T00:00:00</dateTime> 
    <dateTime>2011-03-01T00:00:00</dateTime> 
    <dateTime>2011-04-01T00:00:00</dateTime> 
    </Dates> 
    <Values> 
    <double>0.019974</double> 
    <double>0.005395</double> 
    <double>0.004854</double> 
    </Values> 
    <Description> 
    <string>this is row 1</string> 
    <string>this is row 2</string> 
    <string>this is row 3</string> 
    </Values> 
</ObjectData> 

Pożądany wyjście tabela:

Parameter1 Parameter2  Dates    Values  Description 

Some value Other value 2011-02-01 00:00:00.0 0.019974 this is row 1 
Some value Other value 2011-03-01 00:00:00.0 0.005395 this is row 2 
Some value Other value 2011-04-01 00:00:00.0 0.004854 this is row 3 

Jestem po SELECT SQL używając OPENXML lub xml.nodes() funkcjonalność. Na przykład poniższa instrukcja SELECT powoduje produkcję pomiędzy wartościami i datami (to jest wszystkie permutacje wartości i dat), czego chcę uniknąć.

SELECT 
doc.col.value('Parameter1[1]', 'varchar(20)') Parameter1, 
doc.col.value('Parameter2[1]', 'varchar(20)') Parameter2, 
doc1.col.value('.', 'datetime') Dates , 
doc2.col.value('.', 'float') [Values] 
FROM 
@xml.nodes('/ObjectData') doc(col), 
@xml.nodes('/ObjectData/Dates/dateTime') doc1(col), 
@xml.nodes('/ObjectData/Values/double') doc2(col); 

Odpowiedz

7

Możesz użyć tabeli liczb, aby wybrać pierwszy, drugi, trzeci itd. Wiersz z elementów potomnych. W tym zapytaniu ograniczyłem liczbę wierszy zwróconych do liczby, jeśli podano daty. Jeśli jest więcej wartości lub opisów niż dat, musisz zmodyfikować sprzężenie, aby to uwzględnić.

declare @XML xml = ' 
<ObjectData> 
    <Parameter1>some value</Parameter1> 
    <Parameter2>other value</Parameter2> 
    <Dates> 
    <dateTime>2011-02-01T00:00:00</dateTime> 
    <dateTime>2011-03-01T00:00:00</dateTime> 
    <dateTime>2011-04-01T00:00:00</dateTime> 
    </Dates> 
    <Values> 
    <double>0.019974</double> 
    <double>0.005395</double> 
    <double>0.004854</double> 
    </Values> 
    <Description> 
    <string>this is row 1</string> 
    <string>this is row 2</string> 
    <string>this is row 3</string> 
    </Description> 
</ObjectData>' 

;with Numbers as 
(
    select number 
    from master..spt_values 
    where type = 'P' 
) 
select T.N.value('Parameter1[1]', 'varchar(50)') as Parameter1, 
     T.N.value('Parameter2[1]', 'varchar(50)') as Parameter2, 
     T.N.value('(Dates/dateTime[position()=sql:column("N.Number")])[1]', 'datetime') as Dates, 
     T.N.value('(Values/double[position()=sql:column("N.Number")])[1]', 'float') as [Values], 
     T.N.value('(Description/string[position()=sql:column("N.Number")])[1]', 'varchar(max)') as [Description] 
from @XML.nodes('/ObjectData') as T(N) 
    cross join Numbers as N 
where N.number between 1 and (T.N.value('count(Dates/dateTime)', 'int')) 
+0

Dziękuję bardzo, Mikael. Działa to naprawdę! Składnia jest wciąż zadziwiająca, wyobrażałem sobie, że jest nieco prostsza ... :) – Puzzled

-1

Zazwyczaj, jeśli chciał analizować XML, można zrobić to język programowania, takich jak Perl, Python, Java czy C#, który a) posiada XML DOM, oraz b) mogą komunikować się z relacyjnej bazy danych.

Oto krótki artykuł, który pokazuje niektóre podstawy czytania i pisania XML w języku C# ... i ma nawet przykład, jak utworzyć dokument XML z zapytania SQL (w jednym wierszu!):

http://www.c-sharpcorner.com/uploadfile/mahesh/readwritexmltutmellli2111282005041517am/readwritexmltutmellli21.aspx

+0

Dziękuję, ale to nie jest to, czego szukam. Jestem po instrukcja SQL za pomocą OPENXML lub xml.nodes(). Poniższa instrukcja select powoduje produkcję między wartościami i datami, czego chcę uniknąć. SELECT doc.col.value ('Parametr1 [1]', 'varchar (20)') Parametr1, doc.col.value ('Parametr2 [1]', 'varchar (20)') Parametr2, doc1 .col.value (".", "datetime") Daty , doc2.col.value (". [1]", "float") [Wartości] Z dokumentu @ xml.nodes ('/ ObjectData') (col) , @ xml.nodes ("/ ObjectData/Dates/dateTime") doc1 (col) , @ xml.nodes ('/ ObjectData/Values ​​/ double') doc2 (col); – Puzzled

2

Użyj funkcji OPENXML. Jest dostawcą zestaw wierszy (zwraca zestaw wierszy analizowanych z XML), a zatem mogą być stosowane w SELECT lub INSERT jak:

INSERT INTO table SELECT * FROM OPENXML(source, rowpattern, flags) 

proszę zobaczyć pierwszy przykład w linku dokumentacji dla jasności.