工作中常遇到用oracle解析复杂类型的json(多层对象并且包含数组等)情况,本人在开发中,采用将复杂json逐层解析到表,随后再提取方法。
例:解析如下的json数据,某平台国内机票订购单据
{
"data": {
"AirPortFee": 50.000000,
"CompanyId": "C117507",
"CompanyName": "it测试专用公司",
"FlightInfo": [{
"AirlineName": "南方航空",
"ArrivalDate": "2018-09-05",
"Cabin": "2",
"Clazz": "J",
"DepartureDate": "2018-09-04",
"DestinationCityName": "上海(浦东)",
"FlightNo": "CZ3586",
"OriginCityName": "广州"
}],
"IssuteWay": 0,
"OpName": "陳智偉",
"OrderNo": "TB1800839048",
"OrderSource": 0,
"OrderStatus": "已处理",
"OrderType": 1,
"Passenger": [{
"PassengerAirPortFee": 50.0,
"PassengerCode": "P288725",
"PassengerName": "陈智伟",
"PassengerSalePrice": 3110.0,
"PassengerSaleServicePrice": 0.0,
"PassengerSaleTaxTwo": 10.0,
"PassengerType": "成人",
"TicketNo": "784-2977101969"
}],
"PriceTotal": 3170.000000,
"PurchaseChannelsType": 0,
"SalePrice": 3110.000000,
"SaleServicePrice": 0.000000,
"SaleTaxTwo": 10.000000,
"StartTime": "2018-07-21 10:43"
},
"password": "95aa19fb424fe74275f8608b90afbea344421346",
"timeStamp": "20180721111947904",
"msgType": "TBOrderInfo"
}
构建json解析结果表:
create table TB_JSON_DATA_DETAIL
(
id INTEGER not null,
json_id INTEGER,
path VARCHAR2(200),
kind VARCHAR2(5),
val VARCHAR2(2000),
parent_id INTEGER,
lvl INTEGER,
create_time DATE default sysdate,
item VARCHAR2(200),
seq_no INTEGER
);
构建TB_JSON_DATA_DETAIL表序列:
create sequence JSON_SEQ
minvalue 1
maxvalue 9999999999999999999999999999
start with 1
increment by 1;
创建解析json解析过程:
create or replace procedure pr_json_nest_2(json_id integer,
j apex_json.t_values,
parent_id integer,
path varchar2 default '.',
lvl integer default 1,
seq_no integer default 1) is
v_member varchar2(100);
v apex_json.t_value;
v_path varchar2(1000) := path;
--v_cnt integer;
--v_str varchar2(32700);
v_ret varchar2(1000);
-- v_seq integer;
v_current_id integer;
v_item varchar2(200);
begin
select json_seq.nextval into v_current_id from dual;
/*subtype t_kind is binary_integer range 1 .. 7;
c_null constant t_kind := 1;
c_true constant t_kind := 2;
c_false constant t_kind := 3;
c_number constant t_kind := 4;
c_varchar2 constant t_kind := 5;
c_object constant t_kind := 6;
c_array constant t_kind := 7;
* c_number: number_value contains the number value
* c_varchar2: varchar2_value contains the varchar2 value
* c_object: object_members contains the names of the object's members
* c_array: number_value contains the array length
*/
v := apex_json.get_value(p_path => path, p_values => j);
case
when v.kind is null then
null;
v_ret := apex_json.get_varchar2(p_path => v_path, p_values => j);
when v.kind in (1, 2, 3) then
null;
v_ret := apex_json.get_varchar2(p_path => v_path, p_values => j);
when v.kind = 4 then
v_ret := to_char(v.number_value);
when v.kind = 5 then
v_ret := v.varchar2_value;
when v.kind in (6) then
null;
--get node name
--v_item := substr(v_path, instr(v_path, '.', -1) + 1);
--dbms_output.put_line(v.object_members(1));
for i in 1 .. apex_json.get_count(p_path => path, p_values => j) loop
v_member := v.object_members(i); --apex_json.get_members(p_path => path, p_values => j) (i);
-- dbms_output.put_line(v_member);
if path != '.' then
v_member := path || '.' || v_member;
end if;
pr_json_nest_2(json_id => json_id,
j => j,
parent_id => v_current_id,
path => v_member,
lvl => lvl + 1,
seq_no => i);
end loop;
when v.kind in (7) then
--dbms_output.put_line(v.number_value);
v_ret := to_char(v.number_value);
null;
--dbms_output.put_line(v.object_members(1));
for i in 1 .. v.number_value /*apex_json.get_count(p_path => path, p_values => j)*/
loop
-- v_member := v.object_members(i); --apex_json.get_members(p_path => path, p_values => j) (i);
-- dbms_output.put_line(v_member);
if path != '.' then
v_member := v_path || '[' || i || ']';
end if;
pr_json_nest_2(json_id => json_id,
j => j,
parent_id => v_current_id,
path => v_member,
lvl => lvl + 1,
seq_no => i);
end loop;
else
null;
end case;
--get node item name
v_item := substr(v_path, instr(v_path, '.', -1) + 1);
--store into table
insert into tb_json_data_detail
(id, json_id, path, kind, val, parent_id, lvl, item, seq_no)
values
(v_current_id,
json_id,
v_path,
v.kind,
v_ret,
parent_id,
lvl,
v_item,
seq_no);
commit;
end pr_json_nest_2;
至此,json函数解析过程及json解析结果表已经构建完成,此时只需调用解析过程:
declare
j apex_json.t_values;
p_json clob;
p_id number;
BEGIN
p_json:='{"data":{"AirPortFee":50.000000,"CompanyId":"C117507","CompanyName":"it测试专用公司","FlightInfo":[{"AirlineName":"南方航空","ArrivalDate":"2018-09-05","Cabin":"2","Clazz":"J","DepartureDate":"2018-09-04","DestinationCityName":"上海(浦东)","FlightNo":"CZ3586","OriginCityName":"广州"}],"IssuteWay":0,"OpName":"陳智偉","OrderNo":"TB1800839048","OrderSource":0,"OrderStatus":"已处理","OrderType":1,"Passenger":[{"PassengerAirPortFee":50.0,"PassengerCode":"P288725","PassengerName":"陈智伟","PassengerSalePrice":3110.0,"PassengerSaleServicePrice":0.0,"PassengerSaleTaxTwo":10.0,"PassengerType":"成人","TicketNo":"784-2977101969"}],"PriceTotal":3170.000000,"PurchaseChannelsType":0,"SalePrice":3110.000000,"SaleServicePrice":0.000000,"SaleTaxTwo":10.000000,"StartTime":"2018-07-21 10:43"},"password":"95aa19fb424fe74275f8608b90afbea344421346","timeStamp":"20180721111947904","msgType":"TBOrderInfo"}' ;
p_id :=1;
apex_json.parse(j, p_json);
--调用递归
pr_json_nest_2(json_id => p_id,
j => j,
parent_id => null,
path => '.',
lvl => 1);
end;
提取数据,验证解析结果:p_id为上诉传参id
--订票主信息
select *
from (select /*a.parent_id,*/
a.val, a.item
from tb_json_data_detail a
where json_id = 1 --p_id
and lvl = 3)
pivot(max(val)
for item in('PurchaseChannelsType',
'IssuteWay',
'OrderNo',
'OrderType',
'OrderStatus',
-- 'FlightInfo',
'CompanyId',
'CompanyName',
'OpName',
-- 'Passenger',
'SaleServicePrice',
'AirPortFee',
'SalePrice',
'SaleTaxTwo',
'PriceTotal',
'OrderSource',
'StartTime'));
--FLIGHT
select
AirlineName,
ArrivalDate,
Cabin,
Clazz,
DepartureDate,
DestinationCityName,
FlightNo,
OriginCityName
from (select a.parent_id,
a.val,
a.item,
(select item
from tb_json_data_detail b
where b.id = a.parent_id) parent_item
from tb_json_data_detail a
where json_id = 1 --p_id
and lvl = 5)
pivot(max(val)
for item in('AirlineName' as AirlineName,
'ArrivalDate' as ArrivalDate,
'Cabin' as Cabin,
'Clazz' as Clazz,
'DepartureDate' as DepartureDate,
'DestinationCityName' as DestinationCityName,
'FlightNo' as FlightNo,
'OriginCityName' as OriginCityName))
where regexp_like(parent_item, 'FlightInfo\[[[:digit:]]\]');
---PASSENGER
select
PassengerCode,
PassengerType,
PassengerSaleServicePrice,
PassengerAirPortFee,
PassengerSalePrice,
PassengerSaleTaxTwo,
PassengerName,
TicketNo
from (select a.parent_id,
a.val,
a.item,
(select item
from tb_json_data_detail b
where b.id = a.parent_id) parent_item
from tb_json_data_detail a
where json_id = 1 --p_id
and lvl = 5)
pivot(max(val)
for item in('PassengerAirPortFee' as PassengerAirPortFee,
'PassengerCode' as PassengerCode,
'PassengerName' as PassengerName,
'PassengerSalePrice' as PassengerSalePrice,
'PassengerSaleServicePrice' as
PassengerSaleServicePrice,
'PassengerSaleTaxTwo' as PassengerSaleTaxTwo,
'PassengerType' as PassengerType,
'TicketNo' as TicketNo))
where regexp_like(parent_item, 'Passenger\[[[:digit:]]\]');