Change XML attribute values in SQL Server XML column - sql

I have a SQL Server database table like the following:-
Id (int) Info(xml)
------------------------
1 <xml....
2 <xml ...
3 <xml ...
The XML in each record in the Info field is something like:-
<CodesParameter xmlns="http://mynamespace.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Data Code="A1" HasMoreData="true">
.
.
</Data>
</CodesParameter>
I would like to be able to change the value of the <Data Code="..."> within the XML and have tried the following query:-
UPDATE MyTable
SET Info.modify('replace value of (Data[1]/#Code)with ("B1")')
WHERE Id = 2
Go
The message backs says that the query has executed successfully, but the value does not change.
I have tried declaring the namespace:-
UPDATE MyTable
SET Info.modify('declare namespace myns="http://mynamespace.com/";
replace value of (/myns:WebTableParameter[1]/myns:DataTable[1]/#Code)with ("B1")')
WHERE Id = 2
Go
But the same result - the message says the query has executed successfully, but nothing has changed.
Any help appreciated.

You have several problems:
you're totally ignoring the XML namespace on the XML document in question (in your original UPDATE)
you're using an incomplete XPath expression for your modify
Try this statement:
;WITH XMLNamespaces(DEFAULT 'http://mynamespace.com/')
UPDATE dbo.MyTable
SET Info.modify('replace value of (/CodesParameter/Data[1]/#Code)[1] with ("B1")')
WHERE Id = 1
Basically, you need to start at the root of the XML document - you've missed (or left out) the <CodesParameter> node entirely. Also: you need to select a single attribute - thus you need another [1] after your parenthesis.
With this statement, I was able to update the XML as desired.

Related

Extract field from XML Data in SQL

I have an issue as I never done that before.
I have an SQL table with the following :
ID int;
xml_record xml;
The xml record is looking like that :
<root xml:space="preserve" id="XXX">
<c1>Data1</c1>
<c2>Data2</c2>
<c3>Data3</c3>
...
<cn>DataN</cn>
</root>
However I tried to use the following query with no success (return null) :
SELECT xml_record.value('c1[1]','varchar(50)') as value_c1
FROM myTable
The problem might come from the "space" but not sure.
You just need to fix the expression:
SELECT xml_record.value('(/root/c1)[1]','varchar(50)') AS value_c1
FROM ...
SELECT
xml_record.value
( '(/root/c1/text())[1])',
'varchar(50)') as value_c1
FROM myTable
else remove the first xml line

Insert XML element with attribute into SQL XML column

I have the following XML data stored in [MyTable].Column1 which is an XML type column.
I want to insert a new element to it:
I'm using the following SQL, it executed successfully but when I query the same column value again, I do not see my new XML element. Do I miss certain syntax for inserting an element with attributes?
UPDATE [MyTable]
SET Column1.modify('insert <Setting Name="H" Value="0"/> as last into (/SettingValues)[1]')
WHERE ID = 'xxxxx'
First of all - for your next question: Please do not post pictures! Try to set up a test-scenario. Please read How to ask a good SQL question and How to create a MCVE.
About your question
Your code - on the first sight - should work. But you obviously modified it to fit to this forum.
DECLARE #myTable TABLE(ID VARCHAR(100),Column1 XML)
INSERT INTO #myTable VALUES
('111'
,'<SettingValues>
<Setting Name="A-name" Value="A-value"/>
</SettingValues>')
, ('222'
,'<SettingValues>
<Setting Name="A-name" Value="A-value"/>
</SettingValues>');
UPDATE #MyTable
SET Column1.modify('insert <Setting Name="H" Value="0"/> as last into (/SettingValues)[1]')
WHERE ID = '222';
SELECT *
FROM #myTable
This works as expected.
ID Column1
111 <SettingValues><Setting Name="A-name" Value="A-value" /></SettingValues>
222 <SettingValues><Setting Name="A-name" Value="A-value" /><Setting Name="H" Value="0" /></SettingValues>
After execution you see "1 row affected".
Some ideas:
The filter is not fullfilled
The given XML declares namespaces but never uses them... This is a bit odd. Have you reduced the namespaces and your original XML includes a default namespace (or the elements are prefixed somehow)?
You are checking against the wrong target (other server, other schema, other table...
But: The code above should work...

Extract Value from XML having same tag name in SQL Server

I have XML variable defined below and its value.
I want to fetch the text defined between tag <TextNodeChild> in single query.
Kindly help.
Declare #XMLVariable =
'<?xml version="1.0"?>
<root>
<TextNodeParent>
<TextNodeChild>12345</TextNodeChild>
<TextNodeChild>67890</TextNodeChild>
<TextNodeChild>12389</TextNodeChild>
</TextNodeParent>
</root>'
I need output like this:
12345
67890
12389
You could use the XQuery (i.e. XML query) .nodes() method
SELECT
TextNodeParent = n.value('.[1]', 'NVARCHAR(max)')
FROM
#XMLVariable.nodes('root/TextNodeParent/*') as p(n)
EDIT : If you want to just the select the TextNodeChild node data then little change in xml path as follow
#XMLVariable.nodes('root/TextNodeParent/TextNodeChild') as p(n)
Result
TextNodeParent
12345
67890
12389
#YogeshSharma's solution works - here - because you have nothing but <TextNodeChild> elements under your <TextNodeParent> node.
However, if you had various node, and you wanted to extract only the <TextNodeChild> ones and get their values (and ignore all others), you'd have to use something like this instead:
SELECT
TextNodeParent = XC.value('.', 'INT')
FROM
#XMLVariable.nodes('root/TextNodeParent/TextNodeChild') as XT(XC)

extracting all tags(duplicates also) with specified name from xmltype column in sql

i want to extract a tag from an xml and insert into another table.
this XML is having different name spaces hence i use local-name() to fetch the tag which i want.
but some times there are multiple tags with same name. hence its failing with EXACTFETCH RETURNS MULTIPLE NODES. when multiple tags are existed i want to consider both instead of ignoring the second occurence.
source_table(id, payload):
id : 10
payload :
<root>
<name>john</name>
<status>
<statuscode>1</statuscode>
<statusmessage>one</statusmessage>
<statuscode>2</statuscode>
<statusmessage>two</statusmessage>
</status>
</root>
i want to extract stauscode and message and insert into another table
destination_table(id,name,statuscode,message)
output
10,john,1,one
10,john,2,two
below is the query i used
select id,
extract(payload, '//*[local-name()="name"]'),
extract(payload, '//*[local-name()="statuscode"]'),
extract(payload, '//*[local-name()="statusmessage"]')
from source_table;
i can get first occurence or second occurence by specifying [1] or [2] but i need both the stauscodes to be displayed like below
10,john,1,one
10,john,2,two
any help here
Hope this is what you need: Just past this into an empty query window and execute. Adapt it for your needs:
This solution assumes, that the status codes are sorted (as in your example 1,2,...). If this could occur in random order, just ask again...
Short explanation: The CTE "NameAndCode" brings up the name and the statuscodes. The ROW_NUMBER-function give us the node's index. This index I use to fetch the right message.
One more hint: If you can change the XML's format, it would be better to make the message an attribut of statuscode or to have it as subnode...
DECLARE #xmlColumn XML='<root>
<name>john</name>
<status>
<statuscode>1</statuscode>
<statusmessage>one</statusmessage>
<statuscode>2</statuscode>
<statusmessage>two</statusmessage>
</status>
</root>';
WITH NameAndCode AS
(
SELECT #xmlColumn.value('(/root/name)[1]','varchar(max)') AS Name
,x.y.value('.','int') AS Statuscode
,x.y.query('..') XMLNode
,ROW_NUMBER() OVER(ORDER BY x.y.value('.','int')) AS StatusIndex
FROM #xmlColumn.nodes('/root/status/statuscode') AS x(y)
)
SELECT *
,XMLNode.value('(/status[1]/statusmessage[sql:column("StatusIndex")])[1]','varchar(max)')
FROM NameAndCode

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]')