json_table不是pl/sql函数,只能在sql引擎的from子句中通过横向连接使用;pl/sql中调用它必须用select into或游标获取结果,不能直接赋值或在表达式中使用,因其本质是生成虚拟表而非返回标量。
json_table 不是 pl/sql 函数,它只能在 sql 引擎中执行;所谓“pl/sql 中解析 json”,本质是用 sql 语句把结果查出来再赋值给变量——直接写 json_value(l_json, '$.x') 会报错。
为什么不能在 PL/SQL 表达式里直接调用 JSON_TABLE
JSON_TABLE 是 SQL/JSON 函数,必须出现在 FROM 子句中,且依赖 SQL 引擎的横向连接机制。PL/SQL 执行环境不支持这种行源(row source)行为。
- 你不能写:
l_result := JSON_TABLE(...);—— 编译就失败 - 也不能在
IF或:=右侧直接用它 —— 它不返回标量,而是生成虚拟表 - 真正能用的 JSON 函数只有
JSON_VALUE、JSON_QUERY、JSON_EXISTS这类标量函数,但它们只适合取单值或片段,不适合“展开成多行”
在 PL/SQL 块里正确调用 JSON_TABLE 的唯一方式
用 SELECT ... INTO 或游标从 JSON_TABLE 的结果集中取数据,整个语句必须是合法 SQL,且 JSON_TABLE 必须在 FROM 里。
- 绑定变量要显式转类型:若传入
CLOB,需加FORMAT JSON;若传字符串字面量,确保引号嵌套正确(如'{"a":1}') - 路径表达式不能拼接:Oracle 不支持
'$.' || l_field这种动态路径,得用EXECUTE IMMEDIATE拼完整 SQL 字符串 - 处理空数组或缺失字段时,加
NULL ON EMPTY或MISSING ON ERROR,否则整行消失
DECLARE
l_json CLOB := '{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}';
l_id NUMBER;
l_name VARCHAR2(50);
BEGIN
SELECT jt.id, jt.name
INTO l_id, l_name
FROM JSON_TABLE(
l_json,
'$.users[*]'
COLUMNS (
id NUMBER PATH '$.id',
name VARCHAR2(50) PATH '$.name'
)
) jt
WHERE ROWNUM = 1;
DBMS_OUTPUT.PUT_LINE(l_id || ': ' || l_name);
END;
嵌套数组展开必须用 NESTED PATH,别硬套两层 JSON_TABLE
遇到 {"orders":[{"id":1,"items":[{"sku":"A"},{"sku":"B"}]}]} 这类结构,想让每行带 order.id 和一个 item.sku,用两层 JSON_TABLE 关联容易出笛卡尔积,也难维护。
- 错误做法:先展开
orders得到jt1,再对jt1.items做第二层JSON_TABLE—— 需显式CROSS JOIN,且jt1.items是 JSON 片段,类型易错 - 正确做法:一层
JSON_TABLE+NESTED PATH,路径层级清晰,Oracle 内部自动做关联展开 -
NESTED PATH必须写在COLUMNS内部,不能放在外层路径上;若某 order 的items是null或空数组,默认无记录,加NULL ON EMPTY可保留 order 行
性能与可靠性关键点
实际跑得慢或报错,往往不是语法问题,而是底层约束和数据质量没跟上。
- 确保 JSON 列有
IS JSON约束:没有它,每次查询都要做语法校验,ORA-40442错误频发 - 对高频查询字段建虚拟列 + 索引:比如
ALTER TABLE t ADD (name VARCHAR2(100) GENERATED ALWAYS AS (json_value(json_col, '$.name'))),再在name上建索引 -
COLUMNS中定义的类型必须匹配 JSON 实际值:比如 JSON 里"price": 99.956,定义成NUMBER(3,2)会报ORA-40473;定义成VARCHAR2(5)可能截断 - 路径中别用单引号、尾逗号、HTML 实体——这些都不是标准 JSON,
IS JSON校验通不过
最常被忽略的是:路径里的 $ 是相对路径,不是从根重写;FORMAT JSON 漏写会导致子对象被转成字符串再截断;而 NESTED PATH 的缩进和括号位置稍错,整个语句就编译失败。











