HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

Querying XML nested nodes

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
nestednodesxmlquerying

Problem

I need to integrate a daily XML file into my system.

The XML file has an schema similar to this:

create table txml(id int identity, data xml);
insert into txml (data) values ('

    
    
    
        
        
        
        
        
        
    
    
        
        
       
        
        
    
');


As you can see for each ` section you can find an unknown number of lines. By now I'm doing this job using C# and a .Net console app, but I'd like to do it by using SQL.

Till now I can get a rowset of
tags using the next query:

SELECT  T2.lin.value('(./dLin/@Id)[1]', 'int') Id,
        T2.lin.value('(./dLin/@CoArt)[1]', 'varchar(20)') CoArt,
        T2.lin.value('(./dLin/@CoArtCust)[1]', 'varchar(20)') CoArtCust,
        T2.lin.value('(./lastOrd/@Id)[1]',  'varchar(20)') lastOrderId,
        T2.lin.value('(./lastOrd/@QtyLastOrd)[1]',  'decimal(18,2)') QtyLastOrd
FROM    txml
CROSS APPLY data.nodes('/order/lin') as T2(lin);


That produces next result:

Id | CoArt   | CoArtCust | lastOrderId | QtyLastOrd
-: | :------ | :-------- | :---------- | :---------
 1 | 1111111 | 05220001  | 95767       | 12000.00  
 2 | 2222222 | 05269958  | 49956       | 5000.00


But I should add nested lines corresponding to
` tags and produce the next result:

Id | CoArt   | CoArtCust | lastOrderId | QtyLastOrd | DIni       | DEnd       | NextQty  
-: | :------ | :-------- | :---------- | :--------- | ---------- | ---------- | ---------
 1 | 1111111 | 05220001  | 95767       | 12000.00   | 04/01/2017 | 08/01/2017 | 24000.00  
 1 | 1111111 | 05220001  | 95767       | 12000.00   | 09/01/2017 | 12/01/2017 | 20000.00  
 1 | 1111111 | 05220001  | 95767       | 12000.00   | 13/01/2017 | 16/01/2017 | 24000.00  
 2 | 2222222 | 05269958  | 49956       | 5000.00    | 04/01/2017 | 08/01/2017 | 2200.00  
 2 | 2222222 | 05269958  | 49956       | 5000.00    | 09/01/2017 | 16/01/2017 | 3000.00


I've set up a dbfiddle here

Solution

You can add an additional CROSS APPLY to break out the rows in the way you require:

SELECT  T2.lin.value('(./dLin/@Id)[1]', 'int') Id,
        T2.lin.value('(./dLin/@CoArt)[1]', 'varchar(20)') CoArt,
        T2.lin.value('(./dLin/@CoArtCust)[1]', 'varchar(20)') CoArtCust,
        T2.lin.value('(./lastOrd/@Id)[1]',  'varchar(20)') lastOrderId,
        T2.lin.value('(./lastOrd/@QtyLastOrd)[1]', 'decimal(18,2)') QtyLastOrd,
        T3.lin.value('(./dIni/@Date)[1]', 'date') DIni,
        T3.lin.value('(./dEnd/@Date)[1]', 'date') DEnd,
        T3.lin.value('(./uni/@Qty)[1]', 'decimal(7, 2)') DIni
FROM    txml
CROSS APPLY data.nodes('/order/lin') as T2(lin)
CROSS APPLY T2.lin.nodes('pLin') as T3(lin);


I had to guess the datatype for DIni, correct as required.

Code Snippets

SELECT  T2.lin.value('(./dLin/@Id)[1]', 'int') Id,
        T2.lin.value('(./dLin/@CoArt)[1]', 'varchar(20)') CoArt,
        T2.lin.value('(./dLin/@CoArtCust)[1]', 'varchar(20)') CoArtCust,
        T2.lin.value('(./lastOrd/@Id)[1]',  'varchar(20)') lastOrderId,
        T2.lin.value('(./lastOrd/@QtyLastOrd)[1]', 'decimal(18,2)') QtyLastOrd,
        T3.lin.value('(./dIni/@Date)[1]', 'date') DIni,
        T3.lin.value('(./dEnd/@Date)[1]', 'date') DEnd,
        T3.lin.value('(./uni/@Qty)[1]', 'decimal(7, 2)') DIni
FROM    txml
CROSS APPLY data.nodes('/order/lin') as T2(lin)
CROSS APPLY T2.lin.nodes('pLin') as T3(lin);

Context

StackExchange Database Administrators Q#172951, answer score: 8

Revisions (0)

No revisions yet.