Supply xml element value in modify() method - sql-server

I know how to replace element value for the xml element in the modify() method. Here's the example
TSQL Replace value in XML String
My problem is a bit different. Taking example from above link...
UPDATE dbo.TFS_Feedback_New
SET Details.modify('
replace value of (/optional/educational/text())[1]
with sql:variable("#updatedEducation")')
WHERE feedbackID = #FBID
What I want to do is provide value for 'educational'. In other words I want to do something like this
UPDATE dbo.TFS_Feedback_New
SET Details.modify('
replace value of (/optional/sql:variable("#name")/text())[1]
with sql:variable("#value")')
WHERE feedbackID = #FBID
I'm getting the following error because of sql:variable("#name")
The XQuery syntax '/function()' is not supported.
How can I pass both the name of the element to be updated and its value to my
stored procedure and have it update the XML column?

You are not allowed to use variables as part of the XPath, but you can use a predicate:
DECLARE #xml XML=
N'<root>
<optional>
<educational>SomeText</educational>
<someOther>blah</someOther>
</optional>
</root>';
--The straight approach as you know it:
SET #xml.modify('replace value of (/root/optional/educational/text())[1] with "yeah!"');
SELECT #xml;
--Now we use a variable to find the first node below <optional>, which name is as given:
DECLARE #ElementName VARCHAR(100)='educational';
SET #xml.modify('replace value of (/root/optional/*[local-name()=sql:variable("#ElementName")]/text())[1] with "yeah again!"');
SELECT #xml;
Try it out...

Related

Change value of a xml root node attribute

I am trying to modify the attribute of an XML root attribute in XQuery with T-SQL but I don't manage to do that. My XML has a namespace in it and I can't exactly bypass this. When I query the value of the xml I successfully retrieve the value because I use: ;WITH XMLNAMESPACES (DEFAULT 'some:namespace:here:v1'). I also tried to use: 'declare default element namespace "some:namespace:here:v1";' in the XQuery but does not seem to work.
Any ideas of how can I achieve this ?
This is an example of the XML I am trying to modify.
DECLARE #XML_TO_READ XML = N'
<F2101 xmlns="some:namespace:here:v1" propertyToModify="valueToModify">
<person xmlns="some:namespace:here:v1" anotherPropertyToModify="anotherValueToModify" />
</F2101>'
I retrieve the value like this:
;WITH XMLNAMESPACES (DEFAULT 'some:namespace:here:v1')
SELECT propertyToModify =
#XML_TO_READ.value('(/F2101/#propertyToModify)[1]', 'nvarchar(50)')
And I tried to modify (update) the value like this:
SET #XML_TO_READ.modify('
declare default element namespace "some:namespace:here:v1";
replace value of (/F2101/propertyToModify/text())[1] with ("modifiedValue")')
I tried multiple solutions but I did not find anything that would work for my special case here.
Thanks in advance.
Your statement should be:
SET #XML_TO_READ.modify('
declare default element namespace "some:namespace:here:v1";
replace value of (/F2101/#propertyToModify)[1] with ("modifiedValue")')
Note the "#propertyToModify" rather than "propertyToModify/text()".
Also, documentation link: replace value of (XML DML).

How to get value from node? SQL Server XML dml

#x xml:'
<a number="1">
<b>1</b>
</a>'
I want use query() to get value (can't use value())
#x.query('string(/a[1]/b[1])')
is ok.
#x.query('string(/a[#number="1"]/b)')
throws an error.
Do you have any solution? I want use [#number="1"] to get value.
You can try this.
#x.query('string( (/a[#number="1"]/b)[1])')
In most cases one wants to read more than one value from a given node. You can use a combination of .nodes() (very related to .query(), but returning a derived table) and .query() or .value() like here:
DECLARE #x xml=
N'<a number="1">
<b>1</b>
</a>';
SELECT MyA.value(N'(b/text())[1]','int') AS ReadTheValue
,MyA.query(N'b') QueryTheValue
FROM #x.nodes(N'/a[#number="1"]') AS A(MyA);
You can pass in the search value as a variable like here:
DECLARE #SearchNumber INT=1;
SELECT MyA.value(N'(b/text())[1]','int') AS ReadTheValue
,MyA.query(N'b') QueryTheValue
FROM #x.nodes(N'/a[#number=sql:variable("#SearchNumber")]') AS A(MyA);
If you need nothing else then the value through .query() go with the solution provided by Serkan Aslan. You were just missing to ensure the inner experession to be singleton.
But I must admit, that I have no idea, why one should need this...

How do you add attributes to an existing Root XML Node using TSQL?

I've constructed some XML in TSQL.
declare #requestXML xml
set #requestXML = (
select #dataXML
for xml raw ('rtEvent')
The general output for what I now have follows the pattern resembling this:
<rtEvent>
<ctx>
.....
</ctx>
</rtEvent>
What I'd like to do now is add some attributes and values to the rtEvent root
element node but I'm not certain how to achieve it.
I've looked at the Modify method of the XML object and have observed the insert, replace value of, and delete operations but cannot seem to figure out how to use any of them to achieve the results I'm after.
Basically, I want to be able to modify the root node to reflect something like:
<rtEvent type="customType" email="someaddress#domain.com"
origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>
...
</ctx>
</rtEvent>
Should I be using the documented XML.Modify or is there a better method? How should it be done?
Just in case you wanted to see the modify method way of doing it:
DECLARE #requestXML XML = '<rtEvent><ctx>...</ctx></rtEvent>'
SET #requestXML.modify(
'insert
(
attribute type {"customeType"},
attribute email {"someaddress#domain.com"},
attribute origin {"eCommerce"},
attribute wishedChannel {"0"},
attribute externalId {"5515"}
)
into (/rtEvent)[1]')
SELECT #requestXML
it returns this:
<rtEvent type="customeType" email="someaddress#domain.com" origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>...</ctx>
</rtEvent>
Better use FOR XML PATH, which allows you to specify the naming and aliases as you like them:
SELECT 'SomeContext' AS [ctx]
FOR XML PATH('rtEvent')
This will return this:
<rtEvent>
<ctx>SomeContext</ctx>
</rtEvent>
But with the right attributes you get this:
SELECT 'customType' AS [#type]
,'someaddress#domain.com' AS [#email]
,'eCommerce' AS [#origin]
,0 AS [#wishedChannel]
,5515 AS [#externalId]
,'SomeContext' AS [ctx]
FOR XML PATH('rtEvent')
The result
<rtEvent type="customType" email="someaddress#domain.com" origin="eCommerce" wishedChannel="0" externalId="5515">
<ctx>SomeContext</ctx>
</rtEvent>

SQL XML modify replace

I need help in replacing the XML tag value. Sample code is as follows:
declare #l_runtime_xml XML
declare #l_n_DrillRepID numeric(10)
declare #griddrillparam nvarchar(30)
declare #l_s_DrillBtColumnTag nvarchar(256)
declare #l_s_BTNameSecond nvarchar(30)
set #l_n_DrillRepID =1538
set #griddrillparam = 'userID'
set #l_s_DrillBtColumnTag = 'V_userID'
set #l_s_BTNameSecond = 'l_s_userID'
declare #l_runtime_xmlAAA nvarchar(max)
set #l_runtime_xmlAAA = N'<REPORT_RUNTIME_XML><USER_ID>AISHU</USER_ID><SHEET><SHEET_NO>1</SHEET_NO><DRILLTHRU_PARAM><ENT_RPT><ENT_RPT_ID>1537</ENT_RPT_ID><ENT_RPT_NAME>Reddy111</ENT_RPT_NAME><DEFAULT>1</DEFAULT><CRITERIA><DISPLAY/><HIDDEN/></CRITERIA><COLUMN_HEADER>N</COLUMN_HEADER><DISPLAY_BUTTON>N</DISPLAY_BUTTON><PARAMLIST><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>userID</NAME><BT_NAME/><V_userID>(none)</V_userID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>langID</NAME><BT_NAME/><V_langID>(none)</V_langID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>l_s_userID</NAME><BT_NAME/><V_l_s_userID>(none)</V_l_s_userID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>a_i_langID</NAME><BT_NAME/><V_a_i_langID>(none)</V_a_i_langID></PARAM></PARAMLIST></ENT_RPT><ENT_RPT><ENT_RPT_ID>1538</ENT_RPT_ID><ENT_RPT_NAME>Reddy333</ENT_RPT_NAME><DEFAULT>0</DEFAULT><CRITERIA><DISPLAY/><HIDDEN/></CRITERIA><COLUMN_HEADER>N</COLUMN_HEADER><DISPLAY_BUTTON>N</DISPLAY_BUTTON><PARAMLIST><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>userID</NAME><BT_NAME/><V_userID>(none)</V_userID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>langID</NAME><BT_NAME/><V_langID>(none)</V_langID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>l_s_userID</NAME><BT_NAME/><V_l_s_userID>(none)</V_l_s_userID></PARAM><PARAM><COLTYPE/><POSITION>-999</POSITION><BT_COLUMN_NAME/><NAME>a_i_langID</NAME><BT_NAME/><V_a_i_langID>(none)</V_a_i_langID></PARAM></PARAMLIST></ENT_RPT></DRILLTHRU_PARAM></SHEET></REPORT_RUNTIME_XML>'
select #l_runtime_xml = cast(#l_runtime_xmlAAA as XML)
SET #l_runtime_xml.modify('replace value of ((//SHEET/DRILLTHRU_PARAM/ENT_RPT[(ENT_RPT_ID/text())[1] eq sql:variable("#l_n_DrillRepID")]/PARAMLIST/PARAM[(NAME/text())[1] eq sql:variable("#griddrillparam")]/#l_s_DrillBtColumnTag))[1] with sql:variable("#l_s_BTNameSecond")')
set #l_runtime_xmlAAA = cast(#l_runtime_xml as nvarchar(max))
select #l_runtime_xmlAAA
I think your issue is here:
.../#l_s_DrillBtColumnTag))[1]
If I understand this correctly, you are trying to access an element of the name "V_userId" by putting a variable in that place. But this will not work...
Your question is not quite clear to me (and admittably your structure isn't either, it seems too complicated...). And what do you mean with delete the last child of a node?
Your query would be the following:
Find the "ENT_RPT" with the given number, there find the "PARAM" whose name is what's given and on the same level find the element with the name given, which is to be replaced (see local-name()). Replace this with the value given:
SET #l_runtime_xml.modify('replace value of (//SHEET/DRILLTHRU_PARAM/ENT_RPT[ENT_RPT_ID/text()=sql:variable("#l_n_DrillRepID")]/PARAMLIST/PARAM[NAME/text()=sql:variable("#griddrillparam")]/*[local-name(.)=sql:variable("#l_s_DrillBtColumnTag")]/text())[1] with sql:variable("#l_s_BTNameSecond")')
On the first sigth I assume, that you are dealing with named parameters. It was much better to put the value of these parameters in an element with the same name for all of them (e.g. <VALUE>something</VALUE>. They are specified via "NAME" anyway.
And even better was a structure with attributes, something like
...<PARAM Name="userName" position="-999" moreAttributes...>SomeValue</PARAM>
This would make your navigation much easier and less erronous...

SQL Server xml copy values of one node to another

I want to copy the values of one node to another in sql server(2005 and 2008).
e.g if one of the xml data is as below
<Data>
<Name></Name>
<ShortName>Joe</ShortName>
</Data>
the resulting xml should be
<Data>
<Name>Joe</Name>
<ShortName>Joe</ShortName>
the update statement should affect all the rows in the table
appreciate any help
thanks
You have to watch out for Silent XQuery failures.
The problem in this case is that XPath expression (/Data/Name/text())1 returns an empty sequence. ‘Name’ is an empty element (It has no children). Therefore the expression (/Data/Name/text())1 doesn’t point to any existing node. The solution to this problem is to insert a new text node inside the Name element, like this:
DECLARE #myDoc xml
SET #myDoc = '<Data>
<Name></Name>
<Name2>dd</Name2>
<ShortName>Joe</ShortName>
</Data>'
SELECT #myDoc
if (#myDoc.exist('(/Data/Name/text())[1]') = 1) BEGIN
set #myDoc.modify('
replace value of (/Data/Name/text())[1]
with (/Data/ShortName/text())[1]
')
end else begin
set #myDoc.modify('
insert (/Data/ShortName/text())[1]
as first into (/Data/Name)[1]
')
end
SELECT #myDoc
got the solution
update table set col.modify(replace value of (/Name/text())[1] with (/ShortName/text())[1])

Resources