Get an XML from WEB with a SQL DB2 on Iseries - sql

I have to download the XML generated in this page:
https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210923&locale=it
The only parameter is the date in YYYYMMDD format.
I know there are some SQL function to do this, but I don't know how to approce the problem.
EDIT:
I try this:
SELECT * FROM XMLTABLE(
XMLNAMESPACES (DEFAULT 'https://www.backend-rates.ezv.admin.ch/xmldaily',
'https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210922&locale=it' AS "doc" ) ,
'doc/wechselkurse/devise' PASSING XMLPARSE
( DOCUMENT SYSTOOLS.HTTPGETBLOB
('https://www.backend-rates.ezv.admin.ch/dailyrates.xsd'
, ''))
COLUMNS
code Char(3) PATH 'code',
waehrung char(10) PATH 'waehrung' ,
kurs decfloat PATH 'kurz'
)
where code = 'USD'
But I obtain an empty result, can you help me find the error?

Multiple problems, listed below the queries because they kill formatting when not below
SELECT * from
XMLTABLE(
XMLNAMESPACES (DEFAULT 'https://www.backend-rates.ezv.admin.ch/xmldaily'),
'$doc/wechselkurse/devise'
PASSING XMLPARSE
(DOCUMENT SYSTOOLS.HTTPGETCLOB('https://www.backend-rates.ezv.admin.ch/api/xmldaily?d=20210922&locale=it', '')) as "doc"
COLUMNS
code Char(3) PATH '#code',
waehrung char(10) PATH 'waehrung' ,
kurs decfloat PATH 'kurs'
)
where code = 'usd'
You don't need to add your document to namespaces since it's not a namesspace
What you download and parse is not the document but the schema that can validate it
You have to give a name to your document in the xpath expression, that's the use of as 'doc' (and not '$doc' like in my previous answer)
You can refer to that name as $doc in the xpath expression
code is an attribute, you can get it's value using #code
code values are lowercase

Related

SQL FOR JSON: Create line for each object

I'm currently working on a JSON creation on a SQL Server 2016. For this, I use the FOR JSON function.
SELECT TOP 2
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FROM TABLE_NAME
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
This piece of code creates me this:
{"time":"12.00","ID":"16AE8C15-084C-4C84-8F5D-0000193F8E74","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}},{"time":"12.00","ID":"D5667AF4-5922-4D30-9C8A-00001AB928F6","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}}
The problem is, every object gets displayed on line 1, but I would like to have one line per object.
This would look like this:
{"time":"12.00","ID":"16AE8C15-084C-4C84-8F5D-0000193F8E74","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}},
{"time":"12.00","ID":"D5667AF4-5922-4D30-9C8A-00001AB928F6","EVENT":{"ACTION":"action value","CATEGORY":"category value"},"user":{"name":"username"}}
I have not found any snippets to do this. How can I create such a
If you need to build a separate JSON object for each row, you may try the following statement:
SELECT TOP 2
(
SELECT
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS JsonData
FROM TABLE_NAME
But, if the expected ouput is one JSON array (with or without array wrapper) for the entire table, the format of this output is controlled by FOR JSON AUTO. The visual representation of this output (one line per each JSON object) should be made in the presentation layer. Of course, as an additional option using T-SQL, a small string manipulation is a possible solution:
SELECT REPLACE (
(
SELECT TOP 2
'12.00' AS [time]
,GUID AS [ID]
,'action value' AS [EVENT.ACTION]
,'category value' AS [EVENT.CATEGORY]
,'username' AS [user.name]
FROM TABLE_NAME
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
),
'},{',
'},' + CHAR(10) + '{'
)

XML formatting in SQL Server xml path

I am trying to get a particular XML format by querying SQL Server.
My nested query looks like this:
SELECT
#xml = (SELECT
AdmissionID AS "#encounter_number",
'NDIS' AS organisation_code,
'NDIS' AS encounter_type,
(SELECT 'true' as "#delete",
(SELECT 'NDIS' AS class_type, AdmissionDate AS start_date_time
FOR XML PATH ('financial_class'), TYPE)
FOR XML PATH('financial_classes'), TYPE),
(SELECT URNumber AS 'payor/#entity_number', 'Patient' AS slot, CONVERT (varchar(10), AdmissionDate, 126) AS start_date
FOR XML PATH('payor'), ROOT ('payors'), ELEMENTS, TYPE),
URNumber AS "recipient/#entity_number",
'H' AS referral_source,
'H' AS separation_status,
AdmissionDate AS start_date_time
FROM
HMS
FOR XML PATH('encounter'), ROOT ('pbrc'), TYPE)
which returns this output:
<pbrc>
<encounter encounter_number="525241">
<organisation_code>NDIS</organisation_code>
<encounter_type>NDIS</encounter_type>
<financial_classes delete="true">
<financial_class>
<class_type>NDIS</class_type>
<start_date_time>2018-06-26T00:00:00</start_date_time>
</financial_class>
</financial_classes>
<payors>
<payor>
<payor entity_number="4208151" />
<slot>Patient</slot>
<start_date>2018-06-26</start_date>
</payor>
</payors>
<recipient entity_number="4208151" />
<referral_source>H</referral_source>
<separation_status>H</separation_status>
<start_date_time>2018-06-26T00:00:00</start_date_time>
</encounter>
</pbrc>
But I am trying to achieve the following format for payor with proper payor closing tag and not the short form,
-<payors>
-<payor>
<payor entity_number="8195991"> </payor>
<slot>Patient</slot>
<start_date>2019-06-01</start_date>
</payor>
</payors>
Any suggestion please?
This was a comment, but I shifted it into the answer:
Are you aware of the fact, that - semantically - there's no difference
between <SomeElement /> and <SomeElement></SomeElement>? Is the
blank between <payor> and </payor> important? In fact, it is up
to the presenting engine, how this will be looking. The same XML might
appear in different shape depeding on the viewer...
You can try something along this:
DECLARE #mockPayor TABLE(enitityNumber INT,slot VARCHAR(100));
INSERT INTO #mockPayor VALUES(123,'slot123')
--This will return the self-closed payor element
SELECT p.enitityNumber AS [payor/#entityNumber]
,p.slot
FROM #mockPayor p
FOR XML PATH('payor')
The result
<payor>
<payor entityNumber="123" />
<slot>slot123</slot>
</payor>
And this will return the proper payor closing tag:
SELECT p.enitityNumber AS [payor/#entityNumber]
,' ' AS [payor]
,p.slot
FROM #mockPayor p
FOR XML PATH('payor');
The result
<payor>
<payor entityNumber="123"> </payor>
<slot>slot123</slot>
</payor>
Some background:
The engine works this down and thinks:
Okay, there is an entityNumber attribute living within a payor element. Well I have to open the payor element and insert the entitiyNumber.
Now there is a slot element. So I have to close the payor without any content and open the slot element.
In the second statement the engine thinks:
Same as above
Now there is some content to be placed into the payor element
Same as above, but replace the bold part with after the content

extract xml tag based on max xpath of list value

I'm attempting to extract a currency value from an xml list, which is at the same level as the maximum value of another tag (within the same list).
I am using Oracle SQL 11gR2.
The maximum value extract is based on the xpath max() function.
I've then attempted to subscript the list (for currency tag) based on the result of the max(), but the currency appears as NULL.
This is a small sample of the data, and the associated xpath's used:
with xml_data as (
select xmltype('<?xml version="1.0" encoding="ISO-8859-1"?>
<SOME_OBJECT xmlns="http://www.example.com/xxyy/">
<ILA>
<PRODUCT_LIST>
<PRODUCT>
<MAP_ENTRY>
<CURRENCY_ENTRY>EUR</CURRENCY_ENTRY>
</MAP_ENTRY>
<INITIAL_VALUE>1.4219777502E8</INITIAL_VALUE>
</PRODUCT>
<PRODUCT>
<MAP_ENTRY>
<CURRENCY_ENTRY>ZAR</CURRENCY_ENTRY>
</MAP_ENTRY>
<INITIAL_VALUE>1.4612991655E8</INITIAL_VALUE>
</PRODUCT>
<PRODUCT>
<MAP_ENTRY>
<CURRENCY_ENTRY>USD</CURRENCY_ENTRY>
</MAP_ENTRY>
<INITIAL_VALUE>1.4712991655E8</INITIAL_VALUE>
</PRODUCT>
</PRODUCT_LIST>
</ILA>
</SOME_OBJECT>') as msg from dual union all
select xmltype('<?xml version="1.0" encoding="ISO-8859-1"?>
<SOME_OBJECT xmlns="http://www.example.com/xxyy/">
<ILA>
<SUBSEQUENT_VALUE>10266</SUBSEQUENT_VALUE>
</ILA>
</SOME_OBJECT>') as msg from dual
)
--
select x.subsequent_value, x.max_initial_value ,x.currency
from xml_data d
,xmltable (xmlnamespaces(default 'http://www.example.com/xxyy/')
,'/SOME_OBJECT' passing d.msg
columns
max_initial_value number path 'max(ILA/PRODUCT_LIST/PRODUCT/INITIAL_VALUE)'
,currency varchar2(3) path 'ILA/PRODUCT_LIST/PRODUCT[INITIAL_VALUE=max(ILA/PRODUCT_LIST/PRODUCT/INITIAL_VALUE)]/MAP_ENTRY/CURRENCY_ENTRY'
,subsequent_value number path 'ILA/SUBSEQUENT_VALUE'
) as x;
So the existing output is:
SQL> #get_max
SUBSEQUENT_VALUE MAX_INITIAL_VALUE CUR
---------------- ----------------- ---
147129917
10266
The first line should include USD.
Any suggestions as to what the xpath should be ?
Your xpath looks fine to me in theory,
im not an expert but there might be a problem here :
your displayed value of MAX_INITIAL_VALUE is 147129917 so it has been rounded right ?
Therefore, it cannot be equal to the actual value of 1.4712991655E8 in your XML object
maybe if there is a round function :
currency varchar2(3) path 'ILA/PRODUCT_LIST/PRODUCT[INITIAL_VALUE=round(max(ILA/PRODUCT_LIST/PRODUCT/INITIAL_VALUE))]/MAP_ENTRY/CURRENCY_ENTRY'
it would probably take a second argument for which decimal to round at if it exists
The full path has to be specified for the max() function, as follows:
ILA/TION/PAWS/PRODUCT_LIST/PRODUCT[INITIAL_VALUE = max(/SOME_OBJECT/ILA/TION/PAWS/PRODUCT_LIST/PRODUCT/INITIAL_VALUE)]/MAP_ENTRY/CURRENCY_ENTRY'
Using the same data from the original post, with a modified SQL statement, that includes the full path shows up the currency:
select x.subsequent_value, x.max_initial_value ,x.currency
from xml_data d
,xmltable (xmlnamespaces(default 'http://www.example.com/xxyy/')
,'/SOME_OBJECT' passing d.msg
columns
p XMLTYPE PATH '.'
, max_initial_value number path 'max(ILA/TION/PAWS/PRODUCT_LIST/PRODUCT/INITIAL_VALUE)'
, currency varchar2(3) path 'ILA/TION/PAWS/PRODUCT_LIST/PRODUCT[INITIAL_VALUE = max(/SOME_OBJECT/ILA/TION/PAWS/PRODUCT_LIST/PRODUCT/INITIAL_VALUE)]/MAP_ENTRY/CURRENCY_ENTRY'
, subsequent_value number path 'ILA/TION/PAWS/SUBSEQUENT_VALUE'
) as x;
SUBSEQUENT_VALUE MAX_INITIAL_VALUE CURRENCY
---------------- ----------------- --------
147129917 USD
10266
Alternatively, playing around with virtual paths might also do the trick, but it will slow down your query.

Sql query with cross join XMLTABLE

Help needed to extract the data below from XML messages. I have table which contains the xml message in clob data type. I am trying using below query but it is not returning any data . I need to extract all the values from xml message.
<iORDERS:iORDERS xmlns:iORDERS="urn:iORDERS-abcdonline-com:Integration:v1">
<ORDER_NOTIFY>
<MESSAGE_DATETIME>2017-06-13T12:20:51+10:00</MESSAGE_DATETIME>
<MESSAGE_SEQ>1</MESSAGE_SEQ>
<MESSAGE_TYPE>PLACED</MESSAGE_TYPE>
<ORDER_HEAD>
<ORDER_ID>1111</ORDER_ID>
<DROP_SHIP_ORDER_NO></DROP_SHIP_ORDER_NO>
<CUSTOMER_ORDER_NO>22222</CUSTOMER_ORDER_NO>
<DISPATCH_LOCATION>
<SKU>2323234</SKU>
<UPC>4549432533626</UPC>
<REQUESTED_QTY>1</REQUESTED_QTY>
<DISPATCH_ASSIGNMENT>7777</DISPATCH_ASSIGNMENT>
<PROVIDER_ID>100</PROVIDER_ID>
<PKG_TYPE>SAT</PKG_TYPE>
</DISPATCH_LOCATION>
</ORDER_HEAD>
</ORDER_NOTIFY>
</iORDERS:iORDERS>
query :
select wor.batch_no,wor.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES(DEFAULT 'urn:iORDERS-abcdonline-com:Integration:v1'),
'iORDERS/ORDER_NOTIFY/ORDER_HEAD/DISPATCH_LOCATION'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path './../../../MESSAGE_TYPE') x;
You need to provide the named namespace identifier rather than a defealt, and your column path is going up one too many levels:
select wo.batch_no,wo.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES('urn:iORDERS-abcdonline-com:Integration:v1' as "iORDERS"),
'iORDERS:iORDERS/ORDER_NOTIFY/ORDER_HEAD/DISPATCH_LOCATION'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path './../../MESSAGE_TYPE') x;
BATCH_NO WEB_SERVICE_NO MESSAGE_TYPE
---------- -------------- ------------------------------------------------------------------------------------------------------------------------
1 2 PLACED
Presumably you're planning on getting for information that that from the XML, and/or expect to have multiple nodes; otherwise, to just get the message type you could simplify to:
select wo.batch_no,wo.web_service_no,x.*
from web_orders wo
cross join XMLTABLE (
XMLNAMESPACES('urn:iORDERS-abcdonline-com:Integration:v1' as "iORDERS"),
'iORDERS:iORDERS/ORDER_NOTIFY'
passing xmltype(wo.xml_message)
columns
MESSAGE_TYPE varchar(120) path 'MESSAGE_TYPE') x;
or even, with a single node:
select wo.batch_no,wo.web_service_no,XMLQuery(
'declare namespace iORDERS="urn:iORDERS-abcdonline-com:Integration:v1"; (: :)
iORDERS:iORDERS/ORDER_NOTIFY/MESSAGE_TYPE/text()'
passing xmltype(wo.xml_message)
returning content).getStringVal() as message_type
from web_orders wo;

SQL query to change file extension in a record containing a file-path?

Given an SQL table Table with a column path, how can I modify values like /dir/subdir/file.aaa => /dir/subdir/file.bbb e.g. modify just the file-extension without having to hard-code the specific file/path into my query?
Seems a perfect fit for regexp_replace :
with t as (select '/dir/subdir/file.aaa' as path from dual
union all select '/dir/subdir.aaa/file.aaa' from dual)
select regexp_replace(path, '[.][^.]*$', '.bbb') path
-- ^^^^ ^^^^^^^^^ ^^^^
-- replace last dot-whatever by the "right" extension
from t
where path like '%.aaa'
-- ^^^^^
-- only for path ending with the "wrong" extension
See http://sqlfiddle.com/#!4/d41d8/37017 for some tests
If the column only contains values that are structured like a file, path the following will work:
update the_table
set path = replace(path, '.aaa', '.bbb')
where path like '%.aaa';
Note that this will also update a value like /dir/subdir.aaa/file.aaa to /dir/subdir.bbb/file.bbb.
Another option is to use a regular expression:
update foo
set file_path = regexp_replace(file_path, '\.aaa$', '.bbb', 1, 0, 'i')
where lower(file_path) like '%.aaa';