2011-11-08 3 views
5

Каким будет правильный способ проанализировать следующий XML-блок в таблице SQL Server в соответствии с желаемым расположением (см. Ниже)? Можно ли сделать это с помощью одного оператора SELECT без UNION или цикла? Любые берущие? Заранее спасибо. Входной XML:Анализ вложенных XML-таблиц в таблицу 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> 

Желаемая выходная таблица:

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 

Я после ЗЕЬЕСТ SQL с помощью OPENXML или xml.nodes() функциональность. Например, следующий оператор SELECT приводит к созданию между значениями и датами (это все перестановки значений и дат), чего я хочу избежать.

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

ответ

7

Вы можете использовать таблицу чисел, чтобы выбрать первую, вторую, третью строку etc из дочерних элементов. В этом запросе я ограничил строки, возвращаемые в число, если указаны даты. Если есть больше значений или описаний, чем дат, вам необходимо изменить соединение, чтобы принять это во внимание.

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

Большое спасибо, Микаэль. Это хорошо работает! Синтаксис по-прежнему ошеломляет, я подумал, что это будет немного проще ... :) – Puzzled

-1

Как правило, если вы хотите, чтобы разобрать XML, вы могли бы сделать это язык программирования, как Perl, Python, Java или C#, что а) имеет XML DOM, и б) могут взаимодействовать с реляционной базой данных.

Вот короткая статья, которая показывает некоторые основы чтения и записи XML в C# ... и даже есть пример того, как создать документ XML из запроса SQL (в одной строке!):

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

+0

Спасибо, но это не то, что я ищу. Я выполняю инструкцию SQL, используя OPENXML или xml.nodes(). Следующий оператор select приводит к созданию между значениями и датами, чего я хочу избежать. SELECT doc.col.value ('Parameter1 [1]', 'varchar (20)') Параметр1, doc.col.value ('Parameter2 [1]', 'varchar (20)') Параметр2, doc1 .col.value ('.', 'datetime') Даты , doc2.col.value ('. [1]', 'float') [Значения] FROM @ xml.nodes ('/ ObjectData') doc (col) , @ xml.nodes ('/ ObjectData/Dates/dateTime') doc1 (col) , @ xml.nodes ('/ ObjectData/Values ​​/ double') doc2 (col); – Puzzled

2

Используйте функцию OPENXML. Он является поставщиком наборов строк (он возвращает набор строк, выделенных из XML), и, таким образом, могут быть использованы в SELECT, или ВСТАВИТЬ как:

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

Пожалуйста, смотрите первый пример в ссылке документации для ясности.

Смежные вопросы