工作中常遇到用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')); ---②航班信息 selectairlinename, 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 parent_item like'flightinfo%'; --③乘客信息 selectpassengercode, 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 parent_item like'passenger%';