如何使用甲骨文 JSON_VALUE
How to use Oracle JSON_VALUE
我正在研究触发器。
declare
v_time number(11, 0);
begin
for i in 0..1
loop
select JSON_VALUE(body, '$.sections[0].capsules[0].timer.seconds') into v_time from bodycontent where contentid=1081438;
dbms_output.put_line(v_time);
end loop;
end;
但是,索引引用不会变成动态的。
like JSON_VALUE(body, '$.sections[i].capsules[i].timer.seconds')
有什么办法可以做到这一点吗?
您需要在 json 路径中串联变量:
JSON_VALUE(body, '$.sections[' || to_char(i) || '].capsules[0].timer.seconds')
我真的不明白你的问题与触发器有什么关系。
您可以使用 JSON_TABLE
:
declare
v_time number(11, 0);
begin
for i in 0..1 loop
SELECT time
INTO v_time
FROM bodycontent b
CROSS APPLY
JSON_TABLE(
b.body,
'$.sections[*]'
COLUMNS (
section_index FOR ORDINALITY,
NESTED PATH '$.capsules[*]'
COLUMNS (
capsule_index FOR ORDINALITY,
time NUMBER(11,0) PATH '$.timer.seconds'
)
)
) j
WHERE j.section_index = i + 1
AND j.capsule_index = i + 1
AND b.contentid=1081438;
dbms_output.put_line(v_time);
end loop;
end;
/
其中,对于测试数据:
CREATE TABLE bodycontent ( body CLOB CHECK ( body IS JSON ), contentid NUMBER );
INSERT INTO bodycontent ( body, contentid ) VALUES (
'{"sections":[
{"capsules":[{"timer":{"seconds":0}},{"timer":{"seconds":1}},{"timer":{"seconds":2}}]},
{"capsules":[{"timer":{"seconds":3}},{"timer":{"seconds":4}},{"timer":{"seconds":5}}]},
{"capsules":[{"timer":{"seconds":6}},{"timer":{"seconds":7}},{"timer":{"seconds":8}}]}]}',
1081438
);
输出:
0
4
或者,您可以只使用查询:
SELECT section_index, capsule_index, time
FROM bodycontent b
CROSS APPLY
JSON_TABLE(
b.body,
'$.sections[*]'
COLUMNS (
section_index FOR ORDINALITY,
NESTED PATH '$.capsules[*]'
COLUMNS (
capsule_index FOR ORDINALITY,
time NUMBER(11,0) PATH '$.timer.seconds'
)
)
) j
WHERE ( j.section_index, j.capsule_index) IN ( (1,1), (2,2) )
AND b.contentid=1081438;
输出:
SECTION_INDEX | CAPSULE_INDEX | TIME
------------: | ------------: | ---:
1 | 1 | 0
2 | 2 | 4
(注意:FOR ORDINALITY
中的索引比JSON路径中的数组索引高1。)
db<>fiddle here
因此,问题是您想要遍历索引(以对角线方式遍历数组数组,仅选取两个元素)- 但 JSON_* 函数不适用于将变量作为数组索引 -他们需要硬编码索引。
PL/SQL 对此有一个答案 - 原生动态 SQL,如下所示。
但是请注意,此方法会针对同一文档重复调用 JSON_VALUE()
。根据实际要求(我假设您的问题中的那个只是为了说明)和文档的大小,单次调用 JSON_TABLE()
可能更有效,如 MT0 的回答所示。如果实际上您确实只是从一个非常大的文档中提取两个标量值,那么两次调用 JSON_VALUE()
可能是合理的,尤其是当文档比此处显示的大得多时;但是如果您从一个不太复杂的文档中提取许多标量值,那么单次调用 JSON_TABLE()
可能会更好,即使最后您没有使用它产生的所有数据。
无论如何 - 作为本机动态的说明 SQL,这里是替代解决方案(使用 MT0 的 table):
declare
v_time number(11, 0);
begin
for i in 0..1 loop
execute immediate q'#
select json_value(body, '$.sections[#' || i ||
q'#].capsules[#' || i || q'#].timer.seconds')
from bodycontent
where contentid = 1081438#'
into v_time;
dbms_output.put_line(v_time);
end loop;
end;
/
0
4
PL/SQL procedure successfully completed.
你可以看下面的例子:
只需在您的控制台中点击此查询并尝试了解实现。
SELECT JSON_VALUE('{
"increment_id": "2500000043",
"item_id": "845768",
"options": [
{
"firstname": "Kevin"
},
{
"firstname": "Okay"
},
{
"lastname": "Test"
}
]
}', '$.options[0].firstname') AS value
FROM DUAL;
我正在研究触发器。
declare
v_time number(11, 0);
begin
for i in 0..1
loop
select JSON_VALUE(body, '$.sections[0].capsules[0].timer.seconds') into v_time from bodycontent where contentid=1081438;
dbms_output.put_line(v_time);
end loop;
end;
但是,索引引用不会变成动态的。
like JSON_VALUE(body, '$.sections[i].capsules[i].timer.seconds')
有什么办法可以做到这一点吗?
您需要在 json 路径中串联变量:
JSON_VALUE(body, '$.sections[' || to_char(i) || '].capsules[0].timer.seconds')
我真的不明白你的问题与触发器有什么关系。
您可以使用 JSON_TABLE
:
declare
v_time number(11, 0);
begin
for i in 0..1 loop
SELECT time
INTO v_time
FROM bodycontent b
CROSS APPLY
JSON_TABLE(
b.body,
'$.sections[*]'
COLUMNS (
section_index FOR ORDINALITY,
NESTED PATH '$.capsules[*]'
COLUMNS (
capsule_index FOR ORDINALITY,
time NUMBER(11,0) PATH '$.timer.seconds'
)
)
) j
WHERE j.section_index = i + 1
AND j.capsule_index = i + 1
AND b.contentid=1081438;
dbms_output.put_line(v_time);
end loop;
end;
/
其中,对于测试数据:
CREATE TABLE bodycontent ( body CLOB CHECK ( body IS JSON ), contentid NUMBER );
INSERT INTO bodycontent ( body, contentid ) VALUES (
'{"sections":[
{"capsules":[{"timer":{"seconds":0}},{"timer":{"seconds":1}},{"timer":{"seconds":2}}]},
{"capsules":[{"timer":{"seconds":3}},{"timer":{"seconds":4}},{"timer":{"seconds":5}}]},
{"capsules":[{"timer":{"seconds":6}},{"timer":{"seconds":7}},{"timer":{"seconds":8}}]}]}',
1081438
);
输出:
0 4
或者,您可以只使用查询:
SELECT section_index, capsule_index, time
FROM bodycontent b
CROSS APPLY
JSON_TABLE(
b.body,
'$.sections[*]'
COLUMNS (
section_index FOR ORDINALITY,
NESTED PATH '$.capsules[*]'
COLUMNS (
capsule_index FOR ORDINALITY,
time NUMBER(11,0) PATH '$.timer.seconds'
)
)
) j
WHERE ( j.section_index, j.capsule_index) IN ( (1,1), (2,2) )
AND b.contentid=1081438;
输出:
SECTION_INDEX | CAPSULE_INDEX | TIME ------------: | ------------: | ---: 1 | 1 | 0 2 | 2 | 4
(注意:FOR ORDINALITY
中的索引比JSON路径中的数组索引高1。)
db<>fiddle here
因此,问题是您想要遍历索引(以对角线方式遍历数组数组,仅选取两个元素)- 但 JSON_* 函数不适用于将变量作为数组索引 -他们需要硬编码索引。
PL/SQL 对此有一个答案 - 原生动态 SQL,如下所示。
但是请注意,此方法会针对同一文档重复调用 JSON_VALUE()
。根据实际要求(我假设您的问题中的那个只是为了说明)和文档的大小,单次调用 JSON_TABLE()
可能更有效,如 MT0 的回答所示。如果实际上您确实只是从一个非常大的文档中提取两个标量值,那么两次调用 JSON_VALUE()
可能是合理的,尤其是当文档比此处显示的大得多时;但是如果您从一个不太复杂的文档中提取许多标量值,那么单次调用 JSON_TABLE()
可能会更好,即使最后您没有使用它产生的所有数据。
无论如何 - 作为本机动态的说明 SQL,这里是替代解决方案(使用 MT0 的 table):
declare
v_time number(11, 0);
begin
for i in 0..1 loop
execute immediate q'#
select json_value(body, '$.sections[#' || i ||
q'#].capsules[#' || i || q'#].timer.seconds')
from bodycontent
where contentid = 1081438#'
into v_time;
dbms_output.put_line(v_time);
end loop;
end;
/
0
4
PL/SQL procedure successfully completed.
你可以看下面的例子:
只需在您的控制台中点击此查询并尝试了解实现。
SELECT JSON_VALUE('{
"increment_id": "2500000043",
"item_id": "845768",
"options": [
{
"firstname": "Kevin"
},
{
"firstname": "Okay"
},
{
"lastname": "Test"
}
]
}', '$.options[0].firstname') AS value
FROM DUAL;