Snowflake Get value from XML column - sql

I am working in Snowflake
I need a specific value from XML
SELECT data_xml,REGEXP_SUBSTR(data_xml,'<pinLessNetworkBin>(.*?)(</pinLessNetworkBin>)',3) as network
FROM "DW"."DB"."TABLE"
My results for now
<pinLessNetworkBin>STAR</pinLessNetworkBin>
I just need the value inside
Here the xml:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:FundingSource xmlns:ns0="www.url.com/be/example/payments/model/Concepts/FundingSource" Id="12887819260" extId="">
<id>3939</id>
<pinLessNetworkBin>STAR</pinLessNetworkBin>
</ns0:FundingSource>
How I can get that value?
Regards

the contents of an XML object is retrieved via GET(object, '$') thus for your regex result GET(parse_xml(network), '$') will get you the content. See GET
or you should really retrieve the pinLessNetworkBin via XMLGET:
SELECT data_xml,
XMLGET(parse_xml(data_xml), 'pinLessNetworkBin') as pinLessNetworkBin
FROM "DW"."DB"."TABLE"
parse_xml(data_xml)
which will give you the <pinLessNetworkBin>STAR</pinLessNetworkBin> thus you want to fetch the contents
SELECT data_xml,
get(XMLGET(parse_xml(data_xml), 'pinLessNetworkBin'), '$') as pinLessNetworkBin
FROM "DW"."DB"."TABLE"
parse_xml(data_xml)
should give you 'STAR'
see the PARSE_XML

Related

i want write a sql query to fetch data between two tags in soap xml which present in the clob column of a oracle table

xml which is present ina clob column of xml_message table :
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:oag="http://gateway.consumerhub.commercial.volvocars.net/oagis" xmlns:oag1="http://www.openapplications.org/oagis" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<oag:UpdateConsumerAndOpportunityData_v1 xmlns:ns3="http://www.ford.com/oagis">
<oag1:ApplicationArea>
<oag1:Sender>
<oag1:LogicalId>Volvo</oag1:LogicalId>
<oag1:Component>Vista</oag1:Component>
<oag1:Task>SyncConsumer</oag1:Task>
<oag1:AuthorizationId>AUTH-SK034</oag1:AuthorizationId>
</oag1:Sender>
<oag1:CreationDateTime>2016-01-27T15:07:47Z</oag1:CreationDateTime>
<oag1:BODId>sk-connect-034</oag1:BODId>
</oag1:ApplicationArea>
<oag:DataArea>
<oag1:Sync confirm="Always">
<oag1:SyncCriteria expressionLanguage="XPath">
<oag1:SyncExpression action="change"/>
</oag1:SyncCriteria>
</oag1:Sync>
<oag:Consumer>
<oag:Header>
<oag:Source>AU</oag:Source>
</oag:Header>
<oag:ConsumerDetails Category="Person">
<oag:ConsumerId/>
<oag:Language>EN</oag:Language>
<oag:PersonDetails>
<oag:FirstName>firstname_email_034</oag:FirstName>
<oag:Surname>sname_email_034</oag:Surname>
</oag:PersonDetails>
<oag:EmailAddress Active="true">ticc888#yahoo.com</oag:EmailAddress>
<oag:EmailAddress Active="true" Usage="Business">ahng2#hotmail.com</oag:EmailAddress>
<oag:EmailAddress Active="true" Usage="Invoice">jsmith#gmail.com</oag:EmailAddress>
</oag:ConsumerDetails>
</oag:Consumer>
</oag:DataArea>
</oag:UpdateConsumerAndOpportunityData_v1>
</soapenv:Body>
</soapenv:Envelope>
Now i want all the email address from this xml to fetch and insert into another table.
this xml contain 3 email address ,i want till n number of email address to be fetched that a xml file will contain
As the linked answer shows, you can use XMLTable to extract multiple values; but you need to define at least the namespaces you use, and construct the XPath properly. So to get just the email addresses you can do:
select x.emailaddress
from xml_message m
cross apply xmltable (
xmlnamespaces (
'http://schemas.xmlsoap.org/soap/envelope/' as "soapenv",
'http://gateway.consumerhub.commercial.volvocars.net/oagis' as "oag",
'http://www.openapplications.org/oagis' as "oag1",
'http://www.ford.com/oagis' as "ns3"
),
'soapenv:Envelope/soapenv:Body/oag:UpdateConsumerAndOpportunityData_v1/oag:DataArea/oag:Consumer/oag:ConsumerDetails/oag:EmailAddress'
passing xmltype(m.xml_clob)
columns
EmailAddress varchar2(64) path '.'
) x;
EMAILADDRESS
ticc888#yahoo.com
ahng2#hotmail.com
jsmith#gmail.com
The XPath doesn't refer to oag1 or ns3 but it doesn't hurt to include them anyway, and you might need them to extract other information from the same XML document.
This also lets you extract multiple values at once; or to filter base on an attribute - you might, for example, only want to include the email addresses with attribute Active set to true, which you can do by adding that condition to the XPath:
'soapenv:Envelope/soapenv:Body/oag:UpdateConsumerAndOpportunityData_v1/oag:DataArea/oag:Consumer/oag:ConsumerDetails/oag:EmailAddress[#Active="true"]'
db<>fiddle
You can read more about manipulating XML in the documentation.

How to filter data from xml content using xpath queries to create a temporary table

I am trying to create a sql query using xpath where i am looking to filter the data i need and put that in a temporary table.
Example:
<superStarsDoc>
<names>
<starname>
<preferredname>pref</preferredname>
<firstNm>Bradd</firstNm>
<lastNm>Pitt</lastNm>
</starname>
</names>
</superStarsDoc>
and i am trying to get something like this but not working
with data(firstName,lastName) as
(
unnest(xpath('/superStarsDoc/names/starname/firstNm[#firstNm="Bradd"]/text()',
(select xmlparse(document superstar_doc))))::text as firstName
,unnest(xpath('/superStarsDoc/names/starname/lastNm[#lastNm="Pitt"]lastNm="/text()',
(select xmlparse(document superstar_doc))))::text as lastName
from dbname.superstartable
)
I tried searching for solution but i did not find anything specific for my requirement, i dont have any attribute to point to that record exactly.
I tried using the following solution but that is not working, i am getting syntax error.
XPath 1.0 to find if an element's value is in a list of values
Note: I typed the code here as i cannot copy paste my code exactly, so please excuse any typos
You should probably fix your XPath with :
/superStarsDoc/names/starname/firstNm[.="Bradd"]/text()
/superStarsDoc/names/starname/lastNm[.="Pitt"]/text()
Generic code :
with superstartable(superstar_doc) as (
values (
'<?xml version="1.0" encoding="UTF-8"?>
<superStarsDoc>
<names>
<starname>
<preferredname>pref</preferredname>
<firstNm>Bradd</firstNm>
<lastNm>Pitt</lastNm>
</starname>
</names>
</superStarsDoc>
'::xml)
)
SELECT
xpath('/superStarsDoc/names/starname/firstNm[.="Bradd"]/text()', superstar_doc)[1] as "first-name",
xpath('/superStarsDoc/names/starname/lastNm[.="Pitt"]/text()', superstar_doc)[1] as "last-name"
from superstartable

PostgresSQL xpath with namespaces

I would like to know how to use the xpath funtion in the following example:
The xml is inside a table called SR_DATA, field XMLDATA of type TEXT
The following is the structure of the xml document:
<?xml version="1.0" encoding="UTF-8"?>
<modulo modelCodeScheme="DocType" modelCodeSchemeVersion="01" modelCodeValue="TYPE_20a" modelCodeMeaning="SCREENING" group="groupname" type="format" xmlns="http://www.expr.com/2008/FMSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<AAAAA modelCodeScheme="MAM" modelCodeSchemeVersion="1" modelCodeValue="AN_MAM_6" modelCodeMeaning="Family1" tipodato="booleano">
<![CDATA[false]]>
</AAAAA>
<BBBBB modelCodeScheme="MAM" modelCodeSchemeVersion="1" modelCodeValue="AN_MAM_8" modelCodeMeaning="Family2" tipodato="booleano">
<![CDATA[false]]>
</BBBBB>
</modulo>
Let's say I want to read the text about the element named AAAAA, so my query looks like this:
SELECT (xpath('/modulo/AAAAA/text()', XMLDATA::xml) AS status
FROM SR_DATA;
My query doesn't raise any error but the resultset is empty; I suppose I have to map the NAMESPACES but I need a hint on how to do it.
You need to specify namespaces in the xpath function. The node contains multiple text nodes; you could combine the nodes together using array_to_string function:
SELECT TRIM(BOTH FROM array_to_string(xpath('/x:modulo/x:AAAAA/text()', XMLDATA::xml, ARRAY[
ARRAY['x', 'http://www.expr.com/2008/FMSchema']
]), ''))
FROM SR_DATA
-- false
Demo on db<>fiddle

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

How to query xml value inside a xml column in SQL server

I have something like following code inside [XMLValue] column of a table called "AlgorithmLog":
<?xml version="1.0" encoding="utf-8"?>
<AdapterInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d1p1="http://schemas.datacontract.org/2004/07/Adapters.Adapter.CloudTrader"
xmlns="http://schemas.datacontract.org/2004/07/Adapters.Adapter"
i:type="d1p1:AlgorithmStatusReport">
<SequenceNumber>0</SequenceNumber>
<TrackingGuid i:nil="true" />
<d1p1:Broker>Default</d1p1:Broker>
...
<d1p1:XMLValue><?xml version="1.0"?><int xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1900</int></d1p1:XMLValue>
</AdapterInfo>
and I want to get the value "1900" inside the node <d1p1:XMLValue>
So here is my query:
WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Adapters.Adapter' AS x,
'http://schemas.datacontract.org/2004/07/Adapters.Adapter.CloudTrader' As p,
'http://schemas.microsoft.com/2003/10/Serialization/'as w)
SELECT
XMLValue.query('(/x:AdapterInfo/p:XMLValue/w:int)[1]')AS [XMLVaule]
FROM AlgorithmLog
But it returns nothing.
Could anyone tell me where I did wrong or how I can do it?
Thank you.
Since you have "encoded" XML inside another XML node, and you cannot automatically cast to the XML datatype using the .value() XQuery method, it all gets a bit involved - but this seems to work for me:
;WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/Adapters.Adapter' AS x,
'http://schemas.datacontract.org/2004/07/Adapters.Adapter.CloudTrader' As p,
'http://schemas.microsoft.com/2003/10/Serialization/'as w)
SELECT
CAST(XmlContent.value('(/x:AdapterInfo/p:XMLValue)[1]', 'varchar(2000)') AS XML).value('(w:int)[1]', 'int') AS [XMLValue]
FROM AlgorithmLog
WHERE ....... -- use whatever condition makes sense for you here