Query XML with stylesheet/namespace included in the xml - sql-server

I have tried several ways to query this data out, but have not been successful. I am on SQL Server 2012. Any help would be appreciated.
<NewDataSet>
<Table>
<_x005B_M_x005D_._x005B_SEQID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:short">200</_x005B_M_x005D_._x005B_SEQID_x005D_>
<_x005B_M_x005D_._x005B_CPID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1002</_x005B_M_x005D_._x005B_CPID_x005D_>
</Table>
</NewDataSet>

It would help to have more details on what exactly you want to get out of this, but here is a start, assuming each Element of the XML represents a row:
DECLARE #SampleData XML = N'
<NewDataSet>
<Table>
<_x005B_M_x005D_._x005B_SEQID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:short">200</_x005B_M_x005D_._x005B_SEQID_x005D_>
<_x005B_M_x005D_._x005B_CPID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1002</_x005B_M_x005D_._x005B_CPID_x005D_>
</Table>
</NewDataSet>
';
DECLARE #Delim VARCHAR(50) = '._x005B_';
DECLARE #DelimLen INT = LEN(#Delim);
;WITH cte AS
(
SELECT xrow.value('local-name(.)', 'VARCHAR(50)') AS [ElementName],
xrow.value('declare namespace xsi="http://www.w3.org/2001/XMLSchema-instance"; (./#xsi:type)[1]', 'VARCHAR(50)') AS [xsi:type],
xrow.value('./text()[1]', N'VARCHAR(50)') AS [ElementValue]
FROM #SampleData.nodes('NewDataSet/Table/*') t(xrow)
)
SELECT *,
SUBSTRING(
cte.ElementName,
CHARINDEX(#Delim, cte.ElementName) + #DelimLen,
CHARINDEX('_',
cte.ElementName,
CHARINDEX(#Delim, cte.ElementName) + #DelimLen + 1) -
(CHARINDEX(#Delim, cte.ElementName) + #DelimLen)
) AS [RowType]
FROM cte;
Output:
ElementName xsi:type ElementValue RowType
_x005B_M_x005D_._x005B_SEQID_x005D_ xs:short 200 SEQID
_x005B_M_x005D_._x005B_CPID_x005D_ xs:string 1002 CPID

declare #demo xml = '<NewDataSet>
<Table>
<_x005B_M_x005D_._x005B_SEQID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:short">200</_x005B_M_x005D_._x005B_SEQID_x005D_>
<_x005B_M_x005D_._x005B_CPID_x005D_ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1002</_x005B_M_x005D_._x005B_CPID_x005D_>
</Table>
</NewDataSet>'
select t.r.value('(./*[local-name()=''_x005B_M_x005D_._x005B_SEQID_x005D_'']/text())[1]','integer') seqid
, t.r.value('(./*[local-name()=''_x005B_M_x005D_._x005B_CPID_x005D_'']/text())[1]','nvarchar(128)') cpid
from #demo.nodes('/*/*') t(r)
SQL Fiddle: http://sqlfiddle.com/#!6/d41d8/21769

Related

Rename xml element with child elements in MS SQL

I try to rename element <Visible> to <IsVisible>, but this SELECT returns element Visible without child elements, how can I get Visible with UserId and RoleId elements?
DECLARE #xml XML =
N'<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FieldId>2200</FieldId>
<Visible xsi:type="UserRole">
<UserId xsi:type="CurrentUserId" />
<RoleId>26</RoleId>
</Visible>
</Root>';
SELECT #xml.query(N'let $nd:=(//*[local-name()="Visible"])[1]
return
<IsVisible> {$nd/#*}
{$nd/text()}
</IsVisible>
')
Try this.
DECLARE #xml XML =
N'<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FieldId>2200</FieldId>
<Visible xsi:type="UserRole">
<UserId xsi:type="CurrentUserId" />
<RoleId>26</RoleId>
</Visible>
</Root>';
SELECT #xml.query(N'let $nd:=(//*[local-name()="Visible"])[1]
return
<IsVisible> {$nd/#*}
{$nd/*}
</IsVisible>
')
You can either use XQuery (FLWOR) or a simple replace
DECLARE #xml XML =
N'<Root xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<FieldId>2200</FieldId>
<Visible xsi:type="UserRole">
<UserId xsi:type="CurrentUserId" />
<RoleId>26</RoleId>
</Visible>
</Root>';
--Works, but will reorganise your namespace declarations
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema' AS xsd
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT #xml.query(N'<Root>
{
for $nd in /Root/*
return
if(local-name($nd)!="Visible") then
$nd
else
<IsVisible>{$nd/#*}
{$nd/*}
</IsVisible>
}
</Root>
');
--Might be easier here
SELECT CAST(
REPLACE(REPLACE(
CAST(#xml AS NVARCHAR(MAX))
,'<Visible ','<IsVisible ')
,'</Visible>','</IsVisible>')
AS XML)

Replace value of one node in array of nodes in T-SQL

If I have a column in a table as xml with the following node structure:
<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>5872525</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>
I can successfully retrieve all records that have a particular MasterObjectId
SELECT p.MyPrimaryKey,
m.value('(MasterObjectId)[1]', 'INT') as MasterObjectID,
p.MasterObjectIDs
FROM PickList p
CROSS APPLY MasterObjectIDs.nodes('//PickListObjectBaseModel') AS t1(m)
WHERE m.value('(MasterObjectId)[1]', 'INT') = 3964405
But how would I replace that number in all matching records if needed?
So in the above example, replace 3964405 with 999
This is bad syntax, but I think it is similar to:
DECLARE #oldId INT = 13131180;
DECLARE #newId INT = 99999;
UPDATE PickList
SET MasterObjectIDs.modify('replace value of
(//PickListObjectBaseModel/MasterObjectId/text()=sql:variable("#oldId"))[1] with sql:variable("#newId")');
Here is the complete solution to replace text nodes based on value
The FROM part will speed it up as it reduces the number of rows that are affected, otherwise it performs the action on all rows
DECLARE #oldId INT = 13131180;
DECLARE #newId INT = 99999;
UPDATE PickList
SET MasterObjectIDs.modify('replace value of
(//PickListObjectBaseModel/MasterObjectId[text() = sql:variable("#oldId")]/text())[1]
with sql:variable("#newId")')
FROM PickList p
CROSS APPLY MasterObjectIDs.nodes('//PickListObjectBaseModel') AS t1(m)
WHERE m.value('(MasterObjectId)[1]', 'INT') = #oldId
Great, that you found a solution (voted it up), just some hints:
A dummy table with three rows:
DECLARE #DummyTable TABLE(ID INT IDENTITY, Comment VARCHAR(100), MasterObjectIDs XML);
INSERT INTO #DummyTable VALUES
('Your example', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>5872525</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>'
)
,('More than one target', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>'
),
('no target', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>1111</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>5872525</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>');
--The variables
DECLARE #oldId INT = 3964405;
DECLARE #newId INT = 99999;
--I use xml.exist(), which is even faster, than your approach to filter target rows:
UPDATE #DummyTable
SET MasterObjectIDs.modify('replace value of
(//PickListObjectBaseModel/MasterObjectId[text() = sql:variable("#oldId")]/text())[1]
with sql:variable("#newId")')
FROM #DummyTable p
WHERE p.MasterObjectIDs.exist('/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel/MasterObjectId[text()=sql:variable("#oldId")]') = 1;
--the result
SELECT ##ROWCOUNT; --good the filter hits only 2 rows
SELECT * FROM #DummyTable; --bad, the XML more than one occurances is not edited everywhere...
If the id you are looking for, might occur more than once in one XML, your approach will not work for all of them, just for the first...
You can either run your statement in a loop, until exist() returns 0, or you might shredd the XML and rebuild it from scratch like here:
WITH UpdateableCTE AS
(
SELECT p.MasterObjectIds AS Original
,B.NewXML
FROM #DummyTable AS p
CROSS APPLY
(
SELECT
(
SELECT CASE WHEN plo.value(N'(MasterObjectId/text())[1]','int')=#oldId THEN #newId ELSE plo.value(N'(MasterObjectId/text())[1]','int') END AS MasterObjectId
,plo.value(N'(IsSelected/text())[1]','nvarchar(max)') AS IsSelected
FROM MasterObjectIDs.nodes(N'/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel') AS A(plo)
FOR XML PATH(N'PickListObjectBaseMode'),ROOT(N'ArrayOfPickListObjectBaseModel'),TYPE
)
) AS B(NewXML)
WHERE p.MasterObjectIDs.exist('/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel/MasterObjectId[text()=sql:variable("#oldId")]') = 1
)
UPDATE UpdateableCTE SET Original=NewXML;
--Only 2 rows are affected
SELECT ##ROWCOUNT; --good the filter hits only 2 rows
SELECT * FROM #DummyTable; --all occurances are switched...

query on xml data type in sql server

I have this structure in my sql server :
<?xml version="1.0" encoding="utf-16"?>
<HydroResultTestParameterView xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ReceptionId>11</ReceptionId>
<CapsuleCompany>BR</CapsuleCompany>
<CapsuleSerialNumber>228154</CapsuleSerialNumber>
<CapsuleType>1</CapsuleType>
<CapsuleBuiltDate>1389</CapsuleBuiltDate>
<CapsuleExpireDate>1405</CapsuleExpireDate>
<GasSystemGeneration>1</GasSystemGeneration>
<Remark>ok</Remark>
</HydroResultTestParameterView>
My datatype of my column in nvarchar(max).So i want to get all of ReceptionId result that has CapsuleCompany=BR .How can i find these result ?
This explicitely selects all nodes using a XPath expression, taking all HydroResultTestParameterView with a sub-element CapsuleCompany with text = "BR": /HydroResultTestParameterView[CapsuleCompany="BR"]/ReceptionId
DECLARE #t TABLE(x XML);
INSERT INTO #t(x)VALUES(N'<HydroResultTestParameterView xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ReceptionId>11</ReceptionId>
<CapsuleCompany>BR</CapsuleCompany>
<CapsuleSerialNumber>228154</CapsuleSerialNumber>
<CapsuleType>1</CapsuleType>
<CapsuleBuiltDate>1389</CapsuleBuiltDate>
<CapsuleExpireDate>1405</CapsuleExpireDate>
<GasSystemGeneration>1</GasSystemGeneration>
<Remark>ok</Remark>
</HydroResultTestParameterView>');
SELECT
n.v.value('.[1]','NVARCHAR(MAX)')
FROM
#t
CROSS APPLY x.nodes('/HydroResultTestParameterView[CapsuleCompany="BR"]/ReceptionId') AS n(v)
SELECT
convert(xml,ResultTest).query('/HydroResultTestParameterView/CapsuleSerialNumber')
FROM
[S].[dbo].[HydrostaticTests]
WHERE
convert(xml,ResultTest).exist('/HydroResultTestParameterView[CapsuleSerialNumber="47274"]') = 1;
//-----------------
SELECT
convert(xml,ResultTest).value('(/HydroResultTestParameterView/CapsuleSerialNumber)[1]', 'int')
FROM
[S].[dbo].[HydrostaticTests]
WHERE
convert(xml,ResultTest).exist('/HydroResultTestParameterView[CapsuleSerialNumber="47274"]') = 1;

Relocate node with value in XML if not exists in mssql

I've got table in mssql, and one column of it contains XML. Most of XML in this column looks like this:
<AuthenticationParams xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyParams>
<Username>AmaryllisAPITest</Username>
<ApplicationId>3</ApplicationId>
</MyParams>
<AlsoParams>
<AuthBehavior>Authorization</AuthBehavior>
<SecretKey>MVHXAQA5kF4Ab9siV4vPA4aVPn1EKhbqIBrpCZx2Hg</SecretKey>
</AlsoParams>
</AuthenticationParams>
I want to relocate AuthBehavior node right after AuthenticationParams node, so it will look like this:
<AuthenticationParams xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AuthBehavior>Authorization</AuthBehavior>
<MyParams>
<Username>AmaryllisAPITest</Username>
<ApplicationId>3</ApplicationId>
</MyParams>
<AlsoParams>
<SecretKey>MVHXAQA5kF4Ab9siV4vPA4aVPn1EKhbqIBrpCZx2Hg</SecretKey>
</AlsoParams>
</AuthenticationParams>
How can I do that? Thanks for any help.
Try this code:
DECLARE #xml xml = '<AuthenticationParams xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyParams>
<Username>AmaryllisAPITest</Username>
<ApplicationId>3</ApplicationId>
</MyParams>
<AlsoParams>
<AuthBehavior>Authorization</AuthBehavior>
<SecretKey>MVHXAQA5kF4Ab9siV4vPA4aVPn1EKhbqIBrpCZx2Hg</SecretKey>
</AlsoParams>
</AuthenticationParams>';
DECLARE #temp TABLE (XmlData xml);
INSERT #temp VALUES (#xml);
UPDATE t
SET XmlData.modify('insert /AuthenticationParams/AlsoParams/AuthBehavior
as first
into (/AuthenticationParams)[1]')
FROM #temp t;
UPDATE t
SET XmlData.modify('delete /AuthenticationParams/AlsoParams/AuthBehavior')
FROM #temp t;
SELECT * FROM #temp;

How to fetch value from XML in SQL Server 2008

I have a XML like below. In this i want to fetch 'Name' value. i.e AAA in SQL Server.
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:out="http://www.google.com">
<soapenv:Body>
<MER xmlns="http://www.google.com/services">
<ns1:RequestHeader xmlns:ns1="http://www.google.com//services">
<ns1:Info>
<ns1:Name>AAA</ns1:Name>
<ns1:TransactionId>Mdow0-NHPHuNu7eiEUxb</ns1:TransactionId>
<ns1:SubmitDateTime>2015-09-12T15:48:44.000Z</ns1:SubmitDateTime>
<ns1:SessionId>Mdow0-NHPHuNu7eiEUxb</ns1:SessionId>
<ns1:Timeout>60</ns1:Timeout>
<ns1:MaxRows>100</ns1:MaxRows>
<ns1:TransactionLog>
<ns1:Info1>1234567</ns1:Info1>
<ns1:Info2>ABC123</ns1:Info2>
</ns1:TransactionLog>
</ns1:Info>
<ns1:CorrelatedData>
<ns1:UserID>ABC123</ns1:UserID>
<ns1:UserRole>My Members</ns1:UserRole>
<ns1:TransactionName>Login</ns1:TransactionName>
<ns1:ClientSubmitDateTime>2010-09-12 11:48:44 PM</ns1:ClientSubmitDateTime>
</ns1:CorrelatedData>
</ns1:RequestHeader>
<SearchCriteria>
<MemberID>123456</MemberID>
</SearchCriteria>
</MER>
SqlFiddleDemo
DECLARE #x XML =
N'<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:out="http://www.google.com">
<soapenv:Body>
<MER xmlns="http://www.google.com/services">
<ns1:RequestHeader xmlns:ns1="http://www.google.com//services">
<ns1:Info>
<ns1:Name>AAA</ns1:Name>
<ns1:TransactionId>Mdow0-NHPHuNu7eiEUxb</ns1:TransactionId>
<ns1:SubmitDateTime>2015-09-12T15:48:44.000Z</ns1:SubmitDateTime>
<ns1:SessionId>Mdow0-NHPHuNu7eiEUxb</ns1:SessionId>
<ns1:Timeout>60</ns1:Timeout>
<ns1:MaxRows>100</ns1:MaxRows>
<ns1:TransactionLog>
<ns1:Info1>1234567</ns1:Info1>
<ns1:Info2>ABC123</ns1:Info2>
</ns1:TransactionLog>
</ns1:Info>
<ns1:CorrelatedData>
<ns1:UserID>ABC123</ns1:UserID>
<ns1:UserRole>My Members</ns1:UserRole>
<ns1:TransactionName>Login</ns1:TransactionName>
<ns1:ClientSubmitDateTime>2010-09-12 11:48:44 PM</ns1:ClientSubmitDateTime>
</ns1:CorrelatedData>
</ns1:RequestHeader>
<SearchCriteria>
<MemberID>123456</MemberID>
</SearchCriteria>
</MER>
</soapenv:Body>
</soapenv:Envelope>';
WITH XMLNAMESPACES(
'http://www.google.com//services' AS ns1
)
SELECT
t.c.value('ns1:Name[1]', 'NVARCHAR(100)') AS name
FROM #x.nodes('//ns1:Info') as t(c);
We can read xml data in SQL Server as below:
DECLARE #xml XML =
'<DataTable>
<Employee>
<ID>100</ID>
<Name>Rohan</Name>
<Age>30</Age>
<Gender>Male</Gender>
<City>Delhi</City>
<State>Delhi</State>
</Employee>
</DataTable>'
SELECT
tbl.col.value('ID[1]', 'smallint') AS ID,
Tbl.Col.value('Name[1]', 'varchar(100)') AS Name,
Tbl.Col.value('Age[1]', 'smallint') AS Age,
Tbl.Col.value('Gender[1]', 'varchar(10)') AS Gender,
Tbl.Col.value('City[1]', 'varchar(50)') AS City,
Tbl.Col.value('State[1]', 'varchar(50)') AS State
FROM #xml.nodes('/DataTable/Employee') tbl(col)
To read more on how to read xml data visit below link
Read xml data as table in SQL Server
In case you want to read xml nodes dynamically with unknown number of elements, visit this link:
Read xml nodes dynamically in SQL Server

Resources