How to get value from XML attribute using Sql:Variable in xquery - sql

I want to get attribute value from XML using Xquery.
MY XML is
<Answers>
<AnswerSet>
<Answer questionId="NodeID">155</Answer>
<Answer questionId="ParentNode" selectedValue="12">Product</Answer>
</AnswerSet>
</Answers>
Below is my query.
DECLARE #Field Varchar(100)
DECLARE #Attribute VARCHAR(100)
SET #Field='ParentNode'
SET #Attribute = 'selectedValue'
SELECT ISNULL(PropertyXML.value('(/Answers/AnswerSet/Answer[#questionId=sql:variable("#Field")])[1]','varchar(max)'),'') ,
ISNULL(PropertyXML.value('(/Answers/AnswerSet/Answer[#questionId=sql:variable("#Field")]/sql:variable(#Attribute) )[1]','varchar(max)'),'')
FROM node
WHERE id=155
below line is working fine with sql:variable
ISNULL(PropertyXML.value('(/Answers/AnswerSet/Answer[#questionId=sql:variable("#Field")])[1]','varchar(max)'),'')
but I am getting error in below line..
ISNULL(PropertyXML.value('(/Answers/AnswerSet/Answer[#questionId=sql:variable("#Field")]/sql:variable(#Attribute) )[1]','varchar(max)'),'')
Any ideas on how to get provided attribute(#Attribute) value in result?

Try something like
ISNULL(#Xml.value('(/Answers/AnswerSet/Answer[#questionId=sql:variable("#Field")]/#*[local-name() = sql:variable("#Attribute")])[1]','varchar(max)'),'')

Related

How to delete an item inside an XML with a certain condition?

I have an XML variable value like this in SQL. (SQL SERVER 18)
DECLARE #result NVARCHAR(55) = '123'
DECLARE #XML XML = '<NewData>
<XML>
<PONo>123</SAPPONo>
<Brand>Goldilucks</Brand>
<Color>Amber Brown</Color>
<Size>L</Size>
<OrderQty>21</OrderQty>
<FinalOrderQty>21</FinalOrderQty>
<Unit>KG</Unit>
<DeliveryDate>2021-07-09T00:00:00+08:00</DeliveryDate>
<BatchNo>GC-L1</BatchNo>
<ExpiryDate>2021-08-23T00:00:00+08:00</ExpiryDate>
</XML>
</NewData>'
I want to remove the
<BatchNo>GC-L1</BatchNo> and <ExpiryDate>2021-08-23T00:00:00+08:00</ExpiryDate>
if the <PONo> = '123'.
How can I achieve that in SQL?
I am trying this solution
SET #XML.modify('delete /NewDataSet/XML/BatchNo'[PONo = sql:variable(#result)])
SET #XML.modify('delete /NewDataSet/XML/ExpiryDate'[PONo = sql:variable(#result)])
But the said items still exist in my XML.
Thank you

Loop and modify xml nodes SQL Server

I want to loop through xml nodes in SQL Server, and create a copy of each node containing ','.
For example, for the following xml :
declare #answerXML xml = '<answers><answer part="1">answer,test0</answer><answer part="1">answer,test1</answer></answers>'
I want to be modified to become the following :
declare #answerXML xml = '<answers><answer part="1">answer,test0</answer><answer part="1">answer, test0</answer><answer part="1">answer,test1</answer><answer part="1">answer, test1</answer></answers>'
(Each node is duplicated, and in the added node, a space is added after the comma).
I was planing in using something like this :
SELECT
T.ref.value('.', 'varchar(256)') AS Answer
FROM
(SELECT
[Xml] = #answerXML.query('for $i in data(/answers/answer)
return element temp { $i }')
) A
CROSS APPLY
A.Xml.nodes('/temp') T(ref)
But no use, it seems it's too complicated.
Can anyone help in how to loop and update XML in T-SQL?
Thank you in advance,
You can try to shred the XML and rebuild it from scratch:
declare #answerXML xml=
'<answers>
<answer part="1">answer,test0</answer>
<answer part="1">answer,test1</answer>
</answers>';
SELECT a.value(N'#part',N'int') AS [answer/#part]
,a.value(N'text()[1]',N'nvarchar(max)') AS [answer]
,''
,a.value(N'#part',N'int') AS [answer/#part]
,REPLACE(a.value(N'text()[1]',N'nvarchar(max)'),',',', ') AS [answer]
FROM #answerXML.nodes(N'/answers/answer') AS A(a)
FOR XML PATH(''),ROOT('answers')
The result
<answers>
<answer part="1">answer,test0</answer>
<answer part="1">answer, test0</answer>
<answer part="1">answer,test1</answer>
<answer part="1">answer, test1</answer>
</answers>

Getting node value in xml column

Please let me know why the following XML query is not fetching any result.
I am trying to get value EffectiveUserName tag.
DECLARE #MyXML XML
SET #MyXML = '<PropertyList xmlns="urn:schemas-microsoft-com:xml-analysis" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<Catalog>name</Catalog>
<Timeout>600</Timeout>
<Format>Native</Format>
<DbpropMsmdFlattened2>false</DbpropMsmdFlattened2>
<Cube>Model</Cube>
<DbpropMsmdOptimizeResponse>1</DbpropMsmdOptimizeResponse>
<DbpropMsmdActivityID>68A6900B-20F8-4A02-AEC3-7C56B2D3C5D5</DbpropMsmdActivityID>
<DbpropMsmdRequestID>A0D1E07F-AE29-4CCA-AEE4-3B79D97CA426</DbpropMsmdRequestID>
<DbpropMsmdCurrentActivityID>68A6900B-20F8-4A02-AEC3-7C56B2D3C5D5</DbpropMsmdCurrentActivityID>
<LocaleIdentifier>1033</LocaleIdentifier>
<EffectiveUserName>userid#domainname.com</EffectiveUserName>
<sspropinitappname>PowerBI</sspropinitappname>
</PropertyList>'
select #MyXML.value('(/PropertyList/EffectiveUserName)[1]','varchar(max)')
Your XML has a default namespace that you must respect and include in your query!
<PropertyList xmlns="urn:schemas-microsoft-com:xml-analysis"
***********************************************
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
Use this code to grab the value you're looking for by defining the default XML namespace for your query:
;WITH XMLNAMESPACES(DEFAULT 'urn:schemas-microsoft-com:xml-analysis')
SELECT
#MyXML.value('(/PropertyList/EffectiveUserName)[1]', 'varchar(50)')
You can ignore the namespace by using *: before the tag names:
select #MyXML.value('(/*:PropertyList/*:EffectiveUserName)[1]','varchar(max)')

SQL Server: How to get the value of a XML element specifying an attribute?

For the usage in a SQL query I need to get the value of a specific XML element. The XML element is specified by its attribute.
My XML elements looks like this:
<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>
and the value I am looking for would be "example" when I specify lang to be "en-US".
I found a way to get this value by using the query() function and afterwards the value() function.
declare #S varchar(max)
set #S =
'<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>'
declare #X xml
set #X = CAST(#S as xml)
select #X.query('/translations/value[#lang="en-US"]').value('.','varchar(max)')
This select statement return the value "example" I am looking for by using the query() and value() function. But is there also a - more convenient - way to only use value() OR query()?
Thank you in advance!
Sure there is...
You also can shorten the declaration:
declare #X xml=
'<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>';
select #X.value('(/translations/value[#lang="en-US"])[1]','varchar(max)');
The point is, that you need a singleton result when you are using .value(). You achieve this by putting the XPath in paranthesis and force the first element to be taken (in this case it's the only element).
Btw: If you need this (and sooner or later you will need this...), you might put the "en-US" as parameter into your query like this:
declare #prm VARCHAR(10)='en_US';
select #X.value('(/translations/value[#lang=sql:variable("#prm")])[1]','varchar(max)');
You can reach the similar, but with a value of the actual query by using sql:column().

Updating XML attribute in SQL Server XML column

I am trying to update a node of in my XML which is stored in a SQL Server XML column, the line below works if my XML is in a XML element but now I somehow need to change it to XML attributes, apparently the line becomes invalid after the change.
Works for XMLElement:
UPDATE [Customers]
SET voucherXML.modify('replace value of (/ArrayOfCampaignVoucher/CampaignVoucher/Qty/text())[1] with "50"')
WHERE voucherXML.value('(/ArrayOfCampaignVoucher/CampaignVoucher/VouCode)[1]', 'nvarchar(50)') = #VoucherCode
I tried changing the statement like this but no luck, no errors but QTY values doesn't get change to the value of #NewQuantity:
UPDATE [Customers]
SET voucherXML='<ArrayOfCampaignVoucher xmlns:xsd="http://www.w3.org/2001/XMLSchema" Qty="' + CAST(#NewQuantity AS NVARCHAR(16)) + '" />'
WHERE voucherXML.value('(/CampaignVoucher/VouCode)[1]', 'nvarchar(50)') = #VoucherCode
This is how my XML looks in the SQL Server XML column:
<ArrayOfCampaignVoucher xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CampaignVoucher VouCode="Vouc001" Qty="16" />
<CampaignVoucher VouCode="Vouc002" Qty="18" />
<CampaignVoucher xsi:nil="true" />
</ArrayOfCampaignVoucher>
You should use the XQuery functions - not string together your XML like this....
Try this instead:
DECLARE #newquantity INT = 55
UPDATE dbo.Customers
SET voucherXML.modify('replace value of (/ArrayOfCampaignVoucher/CampaignVoucher[#VouCode="Vouc002"]/#Qty)[1] with sql:variable("#NewQuantity") ')
This works for me - the Qty attribute of the node with VouCode="Vouc002" gets updated to the value I defined before in a SQL variable
Update: to insert a new <CampaignVoucher> entry, use XQuery something like this:
UPDATE dbo.Customers
SET voucherXML.modify('insert <CampaignVoucher VouCode="Vouc003" Qty="42" />
as last into (/ArrayOfCampaignVoucher)[1]')