2011-11-08 37 views
5

¿Cuál sería la forma correcta de analizar el siguiente bloque XML en la tabla de SQL Server de acuerdo con el diseño deseado (abajo)? ¿Es posible hacerlo con una sola instrucción SELECT, sin UNIÓN o un bucle? ¿Ningún arrendatario? Gracias por adelantado. XML de entrada:Analizando XML anidado en la tabla 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> 

deseado salida de la tabla:

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 

yo después de una instrucción SQL SELECT que utiliza OPENXML o xml.nodes() funcionalidad. Por ejemplo, la siguiente declaración SELECT da como resultado producción entre Valores y Fechas (es decir, todas las permutaciones de Valores y Fechas), que es algo que quiero evitar.

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

Respuesta

7

Puede utilizar una tabla de números para elegir la primera, segunda, tercera fila de elementos secundarios. En esta consulta, he limitado las filas devueltas al número si se proporcionan las fechas. Si hay más valores o descripciones que fechas, debe modificar la unión para tener eso en cuenta.

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

Muchas gracias, Mikael. ¡Funciona bien! La sintaxis sigue siendo alucinante, me imaginaba que sería un poco más simple ... :) – Puzzled

-1

Por lo general, si se quería analizar XML, usted lo haría un lenguaje de programación como Perl, Python, Java o C# que a) tiene un XML DOM, y b) se puede comunicar con una base de datos relacional.

He aquí un breve artículo que muestra algunos de los conceptos básicos de lectura y escritura de XML en C# ... e incluso tiene un ejemplo de cómo crear un documento XML a partir de una consulta SQL (en una sola línea!):

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

+0

Gracias, pero esto no es lo que estoy buscando. Estoy buscando una declaración SQL usando la funcionalidad OPENXML o xml.nodes(). La siguiente declaración de selección da como resultado la producción entre Valores y Fechas, que es algo que quiero evitar. SELECCIONAR doc.col.value ('Parámetro1 [1]', 'varchar (20)') Parámetro1, doc.col.value ('Parámetro2 [1]', 'varchar (20)') Parámetro2, doc1 .col.value ('.', 'datetime') Fechas , doc2.col.value ('. [1]', 'float') [Valores] FROM @ xml.nodes ('/ ObjectData') doc (col) , @ xml.nodes ('/ ObjectData/Dates/dateTime') doc1 (col) , @ xml.nodes ('/ ObjectData/Values ​​/ double') doc2 (col); – Puzzled

2

Utilice la función OPENXML. Es un proveedor de conjunto de filas (que devuelve el conjunto de filas procesados ​​del XML) y por lo tanto puede ser utilizado en SELECT o INSERT como:

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

Por favor ver el primer ejemplo en el enlace de documentación para mayor claridad.