2011-11-08 20 views
5

Quale sarebbe il modo corretto di analizzare il seguente blocco XML nella tabella di SQL Server in base al layout desiderato (sotto)? È possibile farlo con una singola istruzione SELECT, senza UNION o un ciclo? Qualche acquirente? Grazie in anticipo. XML in ingresso:Analisi XML nidificata nella tabella 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> 

desiderata uscita tabella:

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 

Sono dopo un'istruzione SQL SELECT che utilizza OPENXML o xml.nodes() funzionalità. Ad esempio, la seguente istruzione SELECT determina la produzione tra Valori e Date (vale a dire tutte le permutazioni di Valori e Date), che è qualcosa che voglio evitare.

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); 

risposta

7

È possibile utilizzare una tabella di numeri per selezionare la prima, la seconda, la terza riga ecc. Dagli elementi figlio. In questa query ho limitato le righe restituite al numero se date date. Se ci sono più valori o descrizioni rispetto alle date, è necessario modificare il join per tenerne conto.

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

Grazie mille, Mikael. Funziona davvero bene! La sintassi è ancora sconvolgente, ho immaginato che fosse un po 'più semplice ... :) – Puzzled

-1

In genere, se si voleva analizzare XML, lo faresti un linguaggio di programmazione come Perl, Python, Java o C# che a) ha un DOM XML, e b) può comunicare con un database relazionale.

Ecco un breve articolo che vi mostra alcuni dei principi fondamentali di lettura e scrittura di XML in C# ... e ha anche un esempio di come creare un documento XML da una query SQL (in una sola riga!):

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

+0

Grazie, ma questo non è quello che sto cercando. Sono in procinto di un'istruzione SQL che utilizza la funzionalità OPENXML o xml.nodes(). La seguente istruzione select si traduce in produzione tra valori e date, che è qualcosa che voglio evitare. SELECT doc.col.value ('Parametro1 [1]', 'varchar (20)') Parametro1, doc.col.value ('Parametro2 [1]', 'varchar (20)') Parametro2, doc1 .col.value ('.', 'datetime') Date , doc2.col.value ('. [1]', 'float') [Valori] FROM @ xml.nodes ('/ ObjectData') doc (col) , @ xml.nodes ('/ ObjectData/Date/dateTime') doc1 (col) , @ xml.nodes ('/ ObjectData/Values ​​/ double') doc2 (col); – Puzzled

2

Utilizzare la funzione OPENXML. Si tratta di un provider di set di righe (restituisce l'insieme di righe analizzati dal XML) e quindi può essere utilizzato in SELECT o INSERT come:

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

Si prega di vedere il primo esempio nel collegamento documentazione per chiarezza.