SQL XML анализирует разные узлы - PullRequest
0 голосов
/ 24 октября 2019

Я хотел бы попросить вас помочь с анализом XML в SQL, где мой XML выглядит следующим образом, где Load - это parrent, что может повторяться X раз. Мне нужен столбец SerNr, и для каждой строки необходимо связать имя заказа, где итоговая таблица будет выглядеть следующим образом

Пример таблицы:

screenshot example of table

<ImageHistory>    
    <Load targets="2" totalTime="417">
    <Orders>
    <Order name="20548976"/>
    </Orders>
    <Data>
    <Disk SerNr="XXXXXX" Size_mb="228936" LoadSuccessfull="true" /> 
    <Disk SerNr="ZZZZZ" Size_mb="228936" LoadSuccessfull="true" /> 
    </Data>
    </Load>
    </ImageHistory>

sql is

with data as (SELECT CAST(MY_XML AS xml) as MY_XML FROM OPENROWSET(BULK 'addres to xml', SINGLE_BLOB) AS T(MY_XML)), 
datainfo as (
SELECT
MY_XML.Blasting.value(' @name', 'BIGINT') as Size_mb,
MY_XML.Blasting.value('@SerNr', 'varchar(32)') as SerNr
FROM data CROSS APPLY MY_XML.nodes('ImageHistory/Load/Data/Disk') AS MY_XML (Blasting))
select * from datainfo 

спасибо за помощь

Ответы [ 2 ]

0 голосов
/ 25 октября 2019

Вы уже получили свой ответ, но я хочу указать на тот факт, что обратная навигация (с использованием ../../) ужасно медленная с большими структурами .

Я бы предложил это:

A макет для имитации вашей проблемы:

DECLARE @yourTable TABLE(ID INT IDENTITY,YourXml XML);
INSERT INTO @yourTable VALUES 
(N'<ImageHistory>
    <Load targets="2" totalTime="417">
    <Orders>
        <Order name="20548976" />
    </Orders>
    <Data>
        <Disk SerNr="XXXXXX" Size_mb="228936" LoadSuccessfull="true" />
        <Disk SerNr="ZZZZZ" Size_mb="228936" LoadSuccessfull="true" />
    </Data>
    </Load>
</ImageHistory>');

- Запрос

SELECT t.ID
        ,ld.value('@targets','int') AS Load_Targets
        ,ld.value('@totalTime','int') AS Load_TotalTime
        ,ld.value('(Orders/Order/@name)[1]','int') AS Order_Name
        ,dsk.value('@SerNr','nvarchar(100)') AS Disk_SerNr
        ,dsk.value('@Size_mb','nvarchar(100)') AS Disk_Size_mb
        ,dsk.value('@LoadSuccessfull','bit') AS Disk_LoadSuccessfull
FROM @yourTable AS t
CROSS APPLY t.YourXml.nodes('/ImageHistory/Load') A(ld)
CROSS APPLY A.ld.nodes('Data/Disk') B(dsk); 

Идея вкратце:

Первый APPLY опустится до <Load> и вернет все <Load> элементов (если их больше ...

Второй APPLY будет использовать фрагмент, возвращенный первым APPLY и нырнуть глубже до <Disk>.

Мы извлекаем имя ордера (и другие значения), вызывая .value() против первого фрагмента (который является <Load>), и мы извлекаем значения <Disk>, вызывая .value() против фрагмента второго APPLY.

0 голосов
/ 24 октября 2019

Я сохранил XML как файл в файловой системе: e: \ Temp \ DiskSerialNumbers.xml Остальное ниже.

SQL

;WITH XmlFile (Contents) AS
(
   SELECT CAST(BulkColumn AS XML) 
   FROM OPENROWSET(BULK 'e:\Temp\DiskSerialNumbers.xml', SINGLE_BLOB) AS XmlData
)
SELECT c.value('(../../Orders/Order/@name)[1]', 'INT') AS [Name]
    , c.value('@SerNr', 'VARCHAR(20)') AS [SerNr]
FROM XmlFile CROSS APPLY Contents.nodes('/ImageHistory/Load/Data/Disk') AS t(c);

Выход

+----------+--------+
|   Name   | SerNr  |
+----------+--------+
| 20548976 | XXXXXX |
| 20548976 | ZZZZZ  |
+----------+--------+
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...