3
 Declare @MainXml XML = 
 '<?xml version="1.0" encoding="utf-8"?>
 <result>
 <cash number="10">
 <account amt="11.00" status="Closed"/>
 <account amt="12.00" status="Closed"/>                       
 </cash>        
 <cash number="20">
 <account amt="21.00" status="Closed"/>
 <account amt="22.00" status="Closed"/>                       
 </cash>        
 </result>'

I am reading data using following query

Declare @Innerxml xml; 
SELECT @Innerxml = T.c.query('<result>{/result/cash}</result>')
FROM   @MainXml.nodes('result') T(c)

SELECT  
Result.Claim.value('(./@number)[1]','varchar(max)') as C1,
Result.Claim.value('(./@amt)[1]','varchar(max)') as C2,
Result.Claim.value('(./@status)[1]','varchar(max)') as C3   
From @Innerxml.nodes('/result/cash/account') Result(Claim)

I want to read the xml and store in DB as below.

C1   C2     C3
----------------
10   11.00  Closed
10   12.00  Closed
20   21.00  Closed
20   22.00  Closed

but my query returns only NULL in C1 column Please help me here. Thanks in advance

2 Answers 2

2

You should not use the parent axis in XML queries in SQL Server. The query plan created will be O(n2). For every node in the XML all nodes in the XML is checked.

First shred on result/cash and then shred on account in a cross apply.

select C.X.value('@number', 'varchar(max)') as C1,
       A.X.value('@amt', 'varchar(max)') as C2,
       A.X.value('@status', 'varchar(max)') as C3
from @MainXml.nodes('result/cash') as C(X)
  cross apply C.X.nodes('account') as A(X)

I don't see the point of creating a second XML variable. Use @MainXML directly.

Sign up to request clarification or add additional context in comments.

7 Comments

While it sounds logical, I'm not sure this is always true. I reckon I've seen queries with .. sometimes performed better than ones with several applies like this, but I don't have any exact example at the moment. That said, it would be interesting to test it
Also I disagree that plan will be O(n^2), it should be linear, because every node has only one parent
@RomanPekar have a look at stackoverflow.com/questions/24196516/…
thanks, nice answer! As I said, it makes perfect sense that it's better to shred xml like you did here and this is always my first try, I just rememeber that I've seen the situations where parent node works better, but again, no example for now.
@RomanPekar perhaps you had a XML index in place? The plan is different if you do.
|
2

@number is attribute of <cash> but your context node is <account>. You need to go up the XML tree one level to get to <cash> node before accessing the attribute. You can do .. to get to parent of current node in xpath :

SELECT  
Result.Claim.value('(../@number)[1]','varchar(max)') as C1,
Result.Claim.value('(./@amt)[1]','varchar(max)') as C2,
Result.Claim.value('(./@status)[1]','varchar(max)') as C3   
From @Innerxml.nodes('/result/cash/account') Result(Claim)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.