ProcessingJSONwithSQL
ProcessingJSONwithSQL
Paul Tuohy
ComCon Phone: +353 1 282 6230
e-Mail: [email protected]
System i Developer Web: www.systemideveloper.com
5, Oakton Court, www.ComConAdvisor.com
Ballybrack
Co. Dublin
Ireland
Software Ltd.
ar
M
In addition to hosting and speaking at the RPG & DB2 Summit, Paul is an award-winning
n
the world. His articles frequently appear in iProDeveloper, The Four Hundred Guru, RPG
Developer and other leading publications. Paul also hosts the popular iTalk with Tuohy
d
an
podcast interviews.
h
nc
Lu
This presentation may contain small code examples that are furnished as simple
examples to provide an illustration. These examples have not been thoroughly tested
under all conditions. We therefore, cannot guarantee or imply reliability, serviceability,
or function of these programs.
All code examples contained herein are provided to you "as is". THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE EXPRESSLY DISCLAIMED.
© ComCon & System i Developer, LLC 2005-2023 Page 3 of 30
Agenda ComCon
Sample JSON
Consuming JSON
The JSON_TABLE Table Function
JSON_TABLE Examples
23
Generate Column List
20
Get an IFS File with SQL
ch
Generating JSON
M
n
23
20
{ "order_id":10248,
ch
"customer_id":"VINET",
ar
"employee_id":5,
"order_date":"2021-07-04",
M
"required_date":"2021-08-01",
n
"order_details":[
ar
{ "product_id":11,
Le
"unit_price":14.0000,
d
"quantity":12,
an
"discount":0
h
},
nc
{ "product_id":42,
Lu
"unit_price":9.8000,
"quantity":10,
"discount":0
},
{ "product_id":72,
"unit_price":34.8000,
"quantity":5,
"discount":0
}
]
}
© ComCon & System i Developer, LLC 2005-2023 Page 5 of 30
Sample JSON - Slightly More Complex ComCon
{ "agent_Id": "AMAZON",
"batch_Id": "AMZ0001",
"order_count": 2,
23
"orders": [
20
{ "order_id": 10248,
"customer_id": "VINET",
ch
"employee_id": 5,
ar
"order_date": "2021-07-04",
M
"required_date": "2021-08-01",
"order_details": [
n
ar
]
an
},
h
{ "order_id": 10249,
nc
"customer_id": "TOMSP",
Lu
"employee_id": 6,
"order_date": "2021-07-05",
"required_date": "2021-08-16",
"order_details": [
{"product_id": 14, "unit_price": 18.6000, "quantity": 9, "discount": 0},
{"product_id": 51, "unit_price": 42.4000, "quantity": 40, "discount": 0}
]
}
]
}
© ComCon & System i Developer, LLC 2005-2023 Page 6 of 30
23
20
Consume JSON with SQL
ch
ar
M
n
ar
Le
d
an
h
nc
Lu
23
20
ch
ar
M
n
ar
Le
d
an
h
nc
Lu
23
- The column name
20
- The result data type
- A path expression to use to locate the column information
ch
ar
23
20
ch
ar
M
n
ar
select *
Le
23
20
ch
ar
M
COLUMNS (
order_id DECIMAL(11, 0) PATH '$.order_id',
h
nc
23
20
ch
ar
M
select max(length(column_name))
ar
from qsys2.syscolumns
Le
23
- Less legible
20
ch
ar
M
n
ar
Le
d
an
h
nc
Lu
23
20
dcl-s gv_ifs_File SQLType(CLOB_FILE) ccsid(*utf8);
ch
ar
M
n
ar
Le
end-Pi;
h
nc
gv_ifs_File_FO = SQFRD;
gv_ifs_File_NAME = fileName;
gv_ifs_File_NL = %len(fileName);
exec SQL
values :gv_ifs_File into :fileContent;
return fileContent;
end-Proc;
© ComCon & System i Developer, LLC 2005-2023 Page 14 of 30
Writing an IFS File with Embedded SQL ComCon
23
20
dcl-s gv_ifs_File SQLType(CLOB_FILE) ccsid(*utf8);
ch
ar
M
n
ar
Le
end-Pi;
Lu
gv_ifs_File_FO = SQFOVR;
gv_ifs_File_NAME = fileName;
gv_ifs_File_NL = %len(fileName);
exec SQL
values :fileContent into :gv_ifs_File;
return fileContent;
end-Proc;
23
20
ch
using (select *
M
COLUMNS (
ar
COLUMNS (
an
)
)
) AS myJSON) as NEW
on (old.order_id, old.product_id) = (new.order_id, new.product_id)
when NOT MATCHED then
insert (order_id, product_id, unit_price, quantity, discount)
values (new.order_id, new.product_id, new.unit_price, new.quantity, new.discount)
when MATCHED then
update set (unit_price, quantity, discount)
= (new.unit_price, new.quantity, new.discount);
© ComCon & System i Developer, LLC 2005-2023 Page 16 of 30
In RPG - Declare Host Variable and Get JSON ComCon
23
20
dcl-ds order qualified;
order_id like(order_T.order_id);
ch
customer_id like(order_T.customer_id);
ar
employee_id like(order_T.employee_id);
M
order_date like(order_T.order_date);
n
required_date like(order_T.required_date);
ar
num_order_details int(5);
Le
end-ds;
d
an
unit_price like(order_details_T.unit_price);
nc
quantity like(order_details_T.quantity);
Lu
discount like(order_details_T.discount);
end-ds;
myJSON = du_get_ifsFile('/home/paris/jsonstuff/singleorder.json');
© ComCon & System i Developer, LLC 2005-2023 Page 17 of 30
Get Order and Order Details Seperately ComCon
exec SQL
select order_id, customer_id, employee_id, order_date, required_date, 0
into :order
from json_table(:myJSON, '$'
COLUMNS ( order_id DECIMAL(11, 0) PATH '$.order_id',
23
20 customer_id CHAR(5) PATH '$.customer_id',
employee_id DECIMAL(11, 0) PATH '$.employee_id',
order_date DATE PATH '$.order_date',
ch
)) AS myJSON ;
M
exec SQL
declare get_details scroll cursor for
n
ar
)) AS myJSON ;
Lu
exec SQL
open get_details;
exec SQL
fetch first from get_details for 99 rows into :order_details;
order.num_order_details = SQLERRD(3);
exec SQL
close get_details;
© ComCon & System i Developer, LLC 2005-2023 Page 18 of 30
Processing JSON with SQL
Speaker: Paul Tuohy
JSON_TO_BSON
ar
JSON_VALUE
M
n
ar
Aggregate Functions
Le
JSON_OBJECTAGG
d
JSON_ARRAYAGG
an
h
nc
Lu
23
20
ch
ar
M
n
ar
Le
d
an
h
nc
Lu
23
20
ch
ar
M
n
ar
Le
d
an
h
nc
Lu
23
20
ch
ar
M
select json_object(
n
'order_id' : order_id
ar
,'customer_id' : customer_id
Le
,'employee_id' : employee_id
d
,'order_date' : order_date
an
,'required_date' : required_date
,'order_details' :
h
nc
,'unit_price' : unit_price
,'quantity' : quantity
,'discount' : discount
)
from order_details
where order_id = 10248 )
format json)
)
from orders
where order_id = 10248;
Generating the More Complex Sample ComCon
values json_object(
23
'agent_Id': 'AMAZON',
20
'batch_Id': 'AMZ0001',
'order_count': (select count(*) from orders where order_id in (10248, 10249)),
ch
'orders':
ar
'order_id' : order_id
n
,'customer_id' : customer_id
ar
,'employee_id' : employee_id
Le
,'order_date' : order_date
,'required_date' : required_date
d
an
,'order_details' :
json_array( (select json_object(
h
'product_id' : product_id
nc
,'unit_price' : unit_price
Lu
,'quantity' : quantity
,'discount' : discount
)
from order_details
where order_id = 10248 )
format json)
)
from orders
where order_id in (10248, 10249)) format json))
);
Things to Watch Out For in the SQL ComCon
FORMAT JSON
Required when nesting functions
The host variable (to receive the JSON) should be defined as UTF8
The JSON scalar functions return a UTF8 value
If the host variable is greater than 32K, it must be defined as a CLOB
This is an SQL limitation, not an RPG limitation
23
20
ch
// Results in
n
ar
DCL-DS GEN_JSON;
Le
GEN_JSON_LEN UNS(10);
GEN_JSON_DATA CHAR(10000000) CCSID(1208);
d
an
END-DS GEN_JSON;
h
nc
Lu
23
20
dcl-s gv_ifs_File SQLType(CLOB_FILE) ccsid(*utf8);
ch
ar
M
n
ar
Le
end-Pi;
h
nc
gv_ifs_File_FO = SQFRD;
gv_ifs_File_NAME = fileName;
gv_ifs_File_NL = %len(fileName);
exec SQL
values :gv_ifs_File into :fileContent;
return fileContent;
end-Proc;
Writing an IFS File with Embedded SQL ComCon
23
20
dcl-s gv_ifs_File SQLType(CLOB_FILE) ccsid(*utf8);
ch
ar
M
n
ar
Le
end-Pi;
Lu
gv_ifs_File_FO = SQFOVR;
gv_ifs_File_NAME = fileName;
gv_ifs_File_NL = %len(fileName);
exec SQL
values :fileContent into :gv_ifs_File;
return fileContent;
end-Proc;
Processing JSON with SQL
Speaker: Paul Tuohy