我一直在尝试解析我认为相对简单的 JSON 结构,但我在使用 APEX_JSON 包时遇到了困难。
create table sw_json (theclob clob);
insert into sw_json values (
'{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)"
,"value":[
{"@odata.type":"#microsoft.graph.group","displayName":"Group A"}
,{"@odata.type":"#microsoft.graph.group","displayName":"Group B"}
,{"@odata.type":"#microsoft.graph.group","displayName":"Group C"}
]
}');
在12c环境中,在Jon Dixon帖子的帮助下,我已经能够在SQL中通过多种方式解决它。
SELECT name
FROM sw_json
nested theclob.value[*]
columns (name varchar2(100) path '$.displayName')
;
SELECT name
FROM sw_json
left outer join json_table(
theclob
, '$.value[*]' columns (name varchar2(100) path '$.displayName')
) on 1=1
;
NAME
--------
Group A
Group B
Group C
但是,为了使其在 11g 中也能工作,我尝试仅使用 APEX_JSON 来完成此操作。我用感觉像是大锤的方法成功了,但我试图用更直接的路径表达式来整理它。
declare
l_values apex_json.t_values;
l_names APEX_T_VARCHAR2;
lc_clob clob;
lc_index varchar2(200);
ln_cnt number := 1;
begin
select theclob into lc_clob
from sw_json;
apex_json.parse (
p_values => l_values,
p_source => lc_clob
);
dbms_output.put_line('Cnt:'||l_values.count);
dbms_output.put_line('First:'||l_values.First);
lc_index := l_values.First;
for i in 1..l_values.count loop
lc_index := l_values.next(lc_index);
exit when lc_index is null;
-- this seems hacky, relying on data content
if substr(l_values(lc_index).varchar2_value,1,1) ='#' then
lc_index := l_values.next(lc_index);
dbms_output.put_line(i||':'||l_values(lc_index).varchar2_value);
end if;
ln_cnt := ln_cnt +1;
end loop;
end;
/
Cnt:12
First:"@odata.context"
4:Group A
6:Group B
8:Group C
我使用 jsonpath.com 来验证我的表达式,但我似乎无法将其转换为 APEX_JSON 用法 - 我不禁觉得我的想法是错误的。
declare
l_values apex_json.t_values;
l_names APEX_T_VARCHAR2;
lc_clob clob;
lc_index varchar2(200);
ln_cnt number := 1;
begin
select theclob into lc_clob
from sw_json;
apex_json.parse (
p_values => l_values,
p_source => lc_clob
);
dbms_output.put_line('Cnt:'||l_values.count);
dbms_output.put_line('First:'||l_values.First);
dbms_output.put_line('Test:'||apex_json.get_varchar2(p_path => '$.value.[%d][displayName]', p0 => 1));
lc_index := l_values.First;
l_names := apex_json.GET_MEMBERS (
p_values => l_values
-- tried all sorts of variations here to try match the 12c SQL
,p_path => '$.value.[%d][displayName]'
--, '$.value[*]' columns (id varchar2(100) path '$.displayName')
);
dbms_output.put_line('Cnt:'||l_names.count);
lc_index := l_names.first;
for i in 1..l_names.count loop
exit when lc_index is null;
dbms_output.put_line(ln_cnt||':'||l_names(lc_index));
lc_index := l_names.next(lc_index);
ln_cnt := ln_cnt +1;
end loop;
end;
/
无论我使用什么路径表达式,我都会得到一些指示数组返回空的内容。
Cnt:12
First:"@odata.context"
Test:
ORA-06531: Reference to uninitialized collection
尝试稍微不同的循环只会返回 12 个空值
for i in 1..l_values.count loop
lc_str := apex_json.get_varchar2(p_path => 'value.[%d]displayName', p0 => i);
dbms_output.put_line(ln_cnt||':'||lc_str);
ln_cnt := ln_cnt +1;
end loop;
APEX_JSON 不使用“$”。符号——这是暗示的。后续作品。
apex_json.does_exist
并不是真正需要的,但它可以方便地防止抛出异常。
declare
l_values apex_json.t_values;
l_names APEX_T_VARCHAR2;
lc_clob clob;
lc_index varchar2(200);
ln_cnt number := 1;
begin
select theclob into lc_clob
from sw_json;
apex_json.parse (
p_values => l_values,
p_source => lc_clob
);
dbms_output.put_line('Member of value array:'||apex_json.get_count(p_path => 'value', p_values => l_values));
IF apex_json.does_exist(p_path => 'value',p_values => l_values) THEN
FOR r IN 1 .. apex_json.get_count(p_path => 'value', p_values => l_values) LOOP
dbms_output.put_line(apex_json.get_varchar2(p_path => 'value[%d].displayName', p0 => r, p_values => l_values));
END LOOP;
END IF;
end;
/
Member of value array:3
Group A
Group B
Group C