How do I replace an XML Node value? - sql-server

I need to replace 2 XML nodes, both postcodes with their correct value. How do I accomplish this in SQL 2005. The XML is in an XML column.
<customer><postcode>P22 2XH</postcode></customer>
with IP22 2XH
Regards
Rob

Working example to update xml node in a table
create table xml (xml xml);
insert xml values('<customer name="John"><postcode>P22 2XH</postcode></customer>');
insert xml values('<customer name="Doe"><postcode>P22 2XH</postcode></customer>');
insert xml values('<customer name="Jane"><postcode>P9 2XH</postcode></customer>');
UPDATE xml
SET xml.modify('
replace value of (//customer/postcode[text()="P22 2XH"]/text())[1]
with "IP22 2XH" ');
select * from xml;
If you had multiple postcode nodes PER xml-record-column, then you can use the below. SQL Server only allows one xml node replacement per modify, so you need to loop it.
create table xml (salesperson varchar(100), portfolios xml);
insert xml values('jim','
<customer name="John"><postcode>P22 2XH</postcode></customer>
<customer name="Doe"><postcode>P22 2XH</postcode></customer>
<customer name="Jane"><postcode>P9 2XH</postcode></customer>');
insert xml values('mary','
<customer name="Joe"><postcode>Other</postcode></customer>
<customer name="Public"><postcode>P22 2XH</postcode></customer>');
while exists (
select * from xml
cross apply portfolios.nodes('//customer/postcode[text()="P22 2XH"]') n(c))
UPDATE xml
SET portfolios.modify('
replace value of (//customer/postcode[text()="P22 2XH"]/text())[1]
with "IP22 2XH" ');
;
select * from xml

Related

Retrieve specific fields of the imported to SQL Server multiple XMLs

I have multiple XML files with the same structure, I have imported them to SQL Server 2017 with the following commands:
DDL:
CREATE DATABASE xmlFiles
GO
USE xmlFiles
CREATE TABLE tblXMLFiles (IntCol int, XmlData xml);
GO
DML:
USE xmlFiles
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\1.xml', SINGLE_BLOB) AS x;
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\2.xml', SINGLE_BLOB) AS x;
…
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\N.xml', SINGLE_BLOB) AS x;
Now I want to query the data:
USE xmlFiles
GO
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #XML = XmLData FROM tblXMLFiles
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT Surname , GivenNames
FROM OPENXML(#hDoc, 'article/ref-list/ref/mixed-citation')
WITH
(
Surname [varchar](100) 'string-name/surname',
GivenNames [varchar](100) 'string-name/given-names'
)
EXEC sp_xml_removedocument #hDoc
GO
The query is working, but the problem is that it returns the data only when there is only one row in a data source table — tblXMLFiles. If I add more than one row, I get empty result set.
Important:
The situation is changing if I add to the outer SELECT clause (SELECT #XML = XmLData…) the TOP statement, then it returns the queried data of the specific row number, according to the TOP value.
How can I retrieve the data not only when there is one line in the table, but many rows?
FROM OPENXML with the corresponding SPs to prepare and to remove a document is outdated and should not be used any more. Rather use the appropriate methods the XML data type provides.
Without an example of your XML it is quite difficult to offer a solution, but my magic crystal ball tells me, that it might be something like this:
SELECT f.IntCol
,mc.value('(string-name/surname)[1]','nvarchar(max)') AS Surname
,mc.value('(string-name/given-names)[1]','nvarchar(max)') AS GivenNames
FROM dbo.tblXMLFiles AS f
OUTER APPLY f.XmlData.nodes('article/ref-list/ref/mixed-citation') AS A(mc)

SQL process XML performance: Insert into columns in a table

I am having an issue in a SQL procedure and I can't seem to find the proper solution.
The stored procedure is containing one parameter of the XML datatype (name = #data).
An example of the incoming message is the following (the actual message is containing a lot more nodes, but I left them out for simplicity):
<Suppliers xmlns="">
<Supplier>
<IDCONO>3</IDCONO>
<IDSUNO>009999</IDSUNO>
<IDSUTY>0</IDSUTY>
</Supplier>
</Suppliers>
In my SQL database I have a table called "Supplier" and it contains the exact same columns as the nodes in the XML (IDCONO, IDSUNO, IDSUTY,..)
I need to loop over the nodes and insert the data in the columns.
I have implemented the procedure below, but this is giving me a lot of perfomance issues on the bigger files (long processing time, even timeouts):
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT
T.C.value('IDCONO[1]', 'VARCHAR(50)') as IDCONO,
T.C.value('IDSUNO[1]', 'VARCHAR(50)') as IDSUNO,
T.C.value('IDSUTY[1]', 'VARCHAR(50)') as IDSUTY
from #data.nodes('/Suppliers/Supplier') T(C)
Any help is appreciated!
Note that the SQL version is SQL server 2012.
Thanks in advance.
The first I would try is the specify the text() node when using the XML datatype to prevent SQL Server from doing a deep search for text elements.
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT
T.C.value('(IDCONO/text())[1]', 'VARCHAR(50)') as IDCONO,
T.C.value('(IDSUNO/text())[1]', 'VARCHAR(50)') as IDSUNO,
T.C.value('(IDSUTY/text())[1]', 'VARCHAR(50)') as IDSUTY
FROM #data.nodes('/Suppliers/Supplier') T(C)
If that is not good enough I would try OPENXML instead.
DECLARE #idoc INT
EXEC sp_xml_preparedocument #idoc OUT, #data
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT IDCONO, IDSUNO, IDSUTY
FROM OPENXML(#idoc, '/Suppliers/Supplier', 2) WITH
(IDCONO VARCHAR(50),
IDSUNO VARCHAR(50),
IDSUTY VARCHAR(50))
EXEC sp_xml_removedocument #idoc

Update XML stored in a XML column in SQL Server

I have a sample table in SQL Server 2012. I am running some queries against but the .modify() XQuery method is executing but not updating.
Here is the table
For this just trying to update settings to 'NewTest'
This will execute but nothing is updating! Thanks for any help!
Since there is a XML namespace (xmlns:dev="http://www.w3.org/2001/XMLSchema") in your XML document, you must inlcude that in your UPDATE statement!
Try this:
;WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/2001/XMLSchema')
UPDATE XmlTable
SET XmlDocument.modify('replace value of (/Doc/#Settings)[1] with "NewTest"')
WHERE XmlId = 1
You should declare a namespace in your update syntax .Try the below syntax
Declare #Sample table
(xmlCol xml)
Insert into #Sample
values
('<dev:Doc xmlns:dev="http://www.w3.org/2001/XMLSchema"
SchemaVersion="0.1" Settings="Testing" Ttile="Ordering">
<Person id="1">
<FirstName>Name</FirstName>
</Person>
</dev:Doc>')
Select * from #Sample
Update #Sample
SET xmlCol.modify(
'declare namespace ns="http://www.w3.org/2001/XMLSchema";
replace value of (/ns:Doc/#Settings)[1]
with "NewTest"')
Select * from #Sample

Update a table row with XML (SQL Server)

I have a xml file below generated using
SELECT * FROM case WHERE ticketNo=#ticketNo FOR XML RAW,
ELEMENTS
The XML looks like this:
<row>
<ticketNo>1</ticketNo>
<caller>name</caller>
<category>3</category>
<service>4</service>
<workgroup>5</workgroup>
</row>
And I update my table using this query with the same with some value changed
UPDATE case
set caller = xmldoc.caller
set category = xml.category
from OpenXml(#idoc, '/row')
with (ticketNo VARCHAR(50)'./ticketNo',
caller VARCHAR(50) './caller',
category VARCHAR(50) './category') xmldoc
where dbo.tb_itsc_case.ticketNo = xmldoc.ticketNo
Is it possible to update the table without specifying the individual column?
You can not do an update without specifying the columns and you can not get data from XML without specifying what nodes to get the data from.
If you can use the "new" XML data type that was introduced in SQL Server 2005 you can do like this instead.
declare #XML xml =
'<row>
<ticketNo>1</ticketNo>
<caller>name</caller>
<category>3</category>
<service>4</service>
<workgroup>5</workgroup>
</row>'
update [case] set
[caller] = #XML.value('(/row/caller)[1]', 'varchar(50)'),
category = #XML.value('(/row/category)[1]', 'varchar(50)')
where
ticketNo = #XML.value('(/row/ticketNo)[1]', 'varchar(50)')
I was able to use this to update 1 row in a table. It requires you to have all fields specified in the XML. It replaces the existing row with the one specified in the XML.
I wish I could figure out how to do it for only the columns that are in the XML. I work on projects where the fields in the table change frequently and it requires re-specifying all the procedures to list out the column names.
create procedure Update_TableName (#xml xml) as
DECLARE #handle INT
EXEC sp_xml_preparedocument #handle OUTPUT, #xml
DECLARE #ID varchar(255)
SELECT #ID = ID FROM OPENXML (#handle, '/data', 2) WITH TableName
if exists (select 1 from TableName where ID = #ID)
delete from TableName where ID = #ID
Insert into TableName
SELECT * FROM OPENXML (#handle, '/data', 2) WITH TableName
EXEC sp_xml_removedocument #handle
XML:
<data>
<ID>9999</ID>
<Column1>Data</Column1>
<Column2>Data</Column2>
<Column3>Data</Column3>
</data>

sql server 2005 xquery read xml type

I have declared a #xmldata as xml. How to read it? I tried
declare #xmldata as xml
set #xmldata = <root><row ename='abc' eid='1'/></root>
SELECT #XMLDATA
but it returned an error. I want to fetch eid column from the above xml type.
Try this:
declare #xmldata as xml
set #xmldata = '<root><row ename="abc" eid="1"/></root>'
SELECT
#xmldata.value('(/root/row/#eid)[1]', 'int') AS 'EID'
Update: if you need to select from your table and extract something from the XML column, use this approach:
SELECT
tbl.ID,
tbl.XmlColumn.value('(/root/row/#ename)[1]', 'varchar(25)') AS 'EName'
FROM
dbo.YourTable tbl
WHERE
(...some condition here...)

Resources