如何在 Oracle 18c 中高效解析 json?
Posted
技术标签:
【中文标题】如何在 Oracle 18c 中高效解析 json?【英文标题】:How to parse json efficiently in Oracle 18c? 【发布时间】:2019-04-05 12:31:27 【问题描述】:我正在尝试使用JSON_OBJECT_T
、JSON_ARRAY_T
API 解析一个大型 json,它工作正常,但我想要专家建议它是否有效?
我正在添加我的 json 文件并解析如下代码
SampleJson
代码
SET SERVEROUTPUT ON;
DECLARE
l_clob clob;
l_time timestamp;
l_json json_object_t;
l_stops_array json_array_t;
l_stops_arr json_array_t;
routeInfoObj json_object_t;
routeStopArr json_array_t;
BEGIN
SELECT LOG_CLOB INTO l_clob FROM ITV_DEV_LOGS WHERE LOG_ID = 1435334;
l_time := systimestamp;
l_json := json_object_t.parse( l_clob );
dbms_output.put_line( 'Parsing Time: ' || extract(second from( systimestamp - l_time ) ) );
l_stops_array := l_json.get_array('data');
DBMS_OUTPUT.PUT_LINE('Data array: '||l_stops_array.get_size);
FOR i in 0..l_stops_array.get_size-1 loop
l_stops_arr := TREAT(l_stops_array.get(i) AS JSON_OBJECT_T).get_array('routedStops');
DBMS_OUTPUT.PUT_LINE('stops array: '||l_stops_arr.get_size);
FOR j in 0..l_stops_arr.get_size - 1 loop
routeInfoObj := TREAT(l_stops_arr.get(j) AS JSON_OBJECT_T).get_object('routingInfo');
DBMS_OUTPUT.PUT_LINE('Stop : ' || routeInfoObj.get_number('stop'));
routeStopArr := TREAT(l_stops_arr.get(j) AS JSON_OBJECT_T).get_array('routedJobs');
FOR k in 0..routeStopArr.get_size - 1 loop
DBMS_OUTPUT.PUT_LINE('JobRef : ' || TREAT(routeStopArr.get(k) AS JSON_OBJECT_T).get_string('jobRef'));
// update query to update stop value to respective jobRef
end loop;
end loop;
end loop;
END;
它工作正常,但是有没有办法改进这个实现,因为这只是一个示例 json,里面的对象数量可能会达到 2000,而不是一个一个地更新记录,有没有办法一次更新所有记录陈述?
【问题讨论】:
你到底想做什么?只是打印出JSON?或者您是否尝试将数据插入规范化数据模型?如果您尝试更新表,该表的外观如何? JSON 的哪一部分应该进入该表? 请提供一个简单的 json,我们可以使用它来将其简化为一个更简单的问题。另外,请告诉我们您希望看到的输出内容,而不是我们尝试从您的代码中对其进行逆向工程。 @a_horse_with_no_name 我想更新序列列中的“停止”值,json 中的 jobRef 是我的主键,它将帮助我找到记录。 @KaushikNayak 附加的 json 正是我将收到的,如果我添加一个简单的 json,那么我会给你错误的信息,我想用 json 中的“停止”值更新序列列使用 jobRef 值,它是我表中的主键。 所以您想更改实际的 JSON,而不是某个表? 【参考方案1】:您可以使用json_table()
将 JSON 值转换为关系表示。这反过来又可以在 MERGE 语句中使用。
例如以下查询:
select j.*
from itv_dev_logs
cross join json_table(log_clob, '$.data.routedStops[*]'
columns stop_id integer path '$.stopId',
zone_ltf integer path '$.zoneLTF',
info_stop_nr integer path '$.routingInfo.stop',
info_route_ref varchar(20) path '$.routingInfo.routeRef',
info_eta varchar(20) path '$.routingInfo.eta',
info_eta_dt timestamp path '$.routingInfo.etaDateTime',
info_stop_time number path '$.routingInfo.stopTime'
) j
where log_id = 1435334;
返回如下内容:
STOP_ID | ZONE_LTF | INFO_STOP_NR | INFO_ROUTE_REF | INFO_ETA | INFO_ETA_DT | INFO_STOP_TIME | INFO_DIST_PREV_STOP | INFO_BREAK_TIME | INFO_BREAK_DURATION
--------------+----------+--------------+----------------+----------+-------------------------+----------------+---------------------+-----------------+--------------------
1554383571432 | 1 | 1 | R119 | 11:01 | 2019-04-16 11:01:00.000 | 0.08 | 0.27 | 00:00 | 00:00
1554383571515 | 1 | 2 | R119 | 11:07 | 2019-04-16 11:07:00.000 | 0.08 | 0.34 | 00:00 | 00:00
1554383571601 | 1 | 3 | R119 | 11:13 | 2019-04-16 11:13:00.000 | 0.08 | 0 | 00:00 | 00:00
1554383571671 | 1 | 4 | R119 | 11:19 | 2019-04-16 11:19:00.000 | 0.08 | 0 | 00:00 | 00:00
1554383571739 | 1 | 5 | R119 | 11:25 | 2019-04-16 11:25:00.000 | 0.08 | 0 | 00:00 | 00:00
这可以用作更新目标表的 MERGE 语句的来源:
merge into your_target_table tg
using (
select j.*
from itv_dev_logs
cross join json_table(log_clob, '$.data.routedStops[*]'
columns stop_id integer path '$.stopId',
zone_ltf integer path '$.zoneLTF',
info_stop_nr integer path '$.routingInfo.stop',
info_route_ref varchar(20) path '$.routingInfo.routeRef',
info_eta varchar(20) path '$.routingInfo.eta',
info_eta_dt timestamp path '$.routingInfo.etaDateTime',
info_stop_time number path '$.routingInfo.stopTime'
) j
where log_id = 1435334
) t on (t.stop_id = tg.stop_id and ... more join conditions ...)
when matched then update
set stop_nr = t.info_stop_nr,
eta_timestamp = t.eta_dt,
由于您既没有提供目标的结构,也没有提供哪些 JSON 键应该与哪些表列匹配的信息,所以所有列名都只是猜测,您需要用正确的名称替换它们。
【讨论】:
表中有2列,sequence和job_id。序列应该和routingInfo.stop匹配,job_id是我的表的主键,需要和routedJobs.jobRef匹配。 JSON_TABLE 也会提高性能吗? 您能否建议 JSON_TABLE() 是否会提高性能,因为在某些情况下我可能需要更新 2000 条记录? @KinjanBhavsar:单个 MERGE 语句很可能比 2000 条更新语句快。但你需要自己测试以上是关于如何在 Oracle 18c 中高效解析 json?的主要内容,如果未能解决你的问题,请参考以下文章