JSON_TABLE 是 Oracle 12c+ 处理 JSON 的唯一高效标准方式,必须在 FROM 子句中使用,依赖 IS JSON 约束与虚拟列索引提升性能,PL/SQL 仅通过 SELECT INTO 调用其函数。

JSON_TABLE 是 Oracle 12c+ 处理 JSON 的首选方式,不是“可选”,而是唯一高效、标准、可索引的路径。PL/SQL 本身不解析 JSON,它靠 SQL 引擎驱动 JSON_TABLE、JSON_VALUE 等函数完成解析——这点必须先认清,否则后续所有写法都会跑偏。
JSON_TABLE 必须放在 FROM 子句里,不能当普通函数用
常见错误是把 JSON_TABLE 写在 SELECT 列表或 WHERE 条件里,比如:SELECT JSON_TABLE(col, '$') FROM t —— 这会报 ORA-40442(函数无效位置)。它本质是一个表函数,只能出现在 FROM 或 LATERAL 关联中。
正确结构是:
SELECT jt.id, jt.name
FROM t,
JSON_TABLE(t.json_col, '$.users[*]'
COLUMNS (
id NUMBER PATH '$.id',
name VARCHAR2(50) PATH '$.name'
)
) jt-
JSON_TABLE第一个参数可以是列名(如t.json_col)、绑定变量(如:json_str)或字面量(如'{"x":1}'),但不能是拼接字符串(如'{' || col || '}'),否则会丢失IS JSON约束带来的优化 - 路径表达式(第二个参数)是相对根的起点,
'$'表示整个文档,'$[*]'表示顶层数组,'$.data.items[*]'表示嵌套路径下的数组 -
COLUMNS里的每个PATH是相对于上一级路径的相对路径,不是从$重写:若外层路径是'$.data',则name PATH '$.name'实际查的是$.data.name
嵌套数组展开别硬套两层 JSON_TABLE,优先用 NESTED
遇到 {"orders":[{"id":1,"items":[{"sku":"A"},{"sku":"B"}]}]} 这类结构,目标是每行输出 order.id 和一个 item.sku,用两层 JSON_TABLE 关联容易引入笛卡尔积、类型转换麻烦,且难以维护。
Oracle 12.2+ 支持 NESTED 路径语法,一行搞定:
SELECT jt.order_id, jt.sku
FROM JSON_TABLE(:json, '$.orders[*]'
COLUMNS (
order_id NUMBER PATH '$.id',
NESTED "items"[*] COLUMNS (sku VARCHAR2(20) PATH '$.sku')
)
) jt-
NESTED "items"[*]中的双引号仅在 key 含大小写或特殊字符时必需;普通小写字母 key 可写NESTED items[*] - 数组越界默认返回
NULL,不报错;如需严格校验,末尾加ERROR ON ERROR - 若列需返回原始 JSON 片段(如整个
"items"数组),必须声明items_json CLOB FORMAT JSON PATH '$.items',否则 Oracle 会转成字符串并截断
PL/SQL 块里调用 JSON 函数必须走 SELECT INTO,不能直接赋值
PL/SQL 没有原生 JSON 解析器对象。所谓“解析”,本质是借 SQL 引擎执行函数,再把结果拉进 PL/SQL 变量。以下写法是错的:
DECLARE
l_json CLOB := '{"x":1}';
l_val NUMBER;
BEGIN
l_val := json_value(l_json, '$.x'); -- ❌ 编译失败:PL/SQL 不识别该函数为标量函数
END;正确写法必须用 SELECT ... INTO:
DECLARE
l_json CLOB := '{"x":1}';
l_val NUMBER;
BEGIN
SELECT json_value(l_json, '$.x') INTO l_val FROM DUAL;
DBMS_OUTPUT.PUT_LINE(l_val);
END;-
JSON_VALUE、JSON_QUERY、JSON_OBJECT等都必须走SELECT,哪怕只查一个值 - 性能关键点在于:确保 JSON 列上有
IS JSON约束,且对高频查询路径建虚拟列 + 索引,否则每次解析都是全扫描 - 如果卡在 Oracle 11g 或必须动态构造复杂 JSON,才考虑引入第三方库
PL/JSON;12c+ 场景下,它只是备选,不是主力
别忽略 IS JSON 约束和虚拟列索引,否则 JSON 查询慢十倍
没有 IS JSON 约束的 JSON 列,Oracle 无法跳过语法校验,每次调用 JSON_TABLE 都要全量验证合法性,尤其对大 CLOB 是明显瓶颈。
高频查询字段(如 $.user.id)应建虚拟列并索引:
ALTER TABLE t ADD (user_id AS json_value(json_col, '$.user.id')); CREATE INDEX idx_t_user_id ON t(user_id);
-
IS JSON约束必须显式添加:ALTER TABLE t ADD CONSTRAINT chk_json CHECK (json_col IS JSON) - 虚拟列 + 索引后,
WHERE json_value(json_col, '$.user.id') = '123'才能走索引;否则就是全表扫描 - PL/JSON 库完全绕过这些优化机制,纯内存解析,数据量一大就撑不住——这是它和原生函数最实际的分水岭
真正卡住人的从来不是“怎么写”,而是没意识到 Oracle 的 JSON 处理是 SQL 层能力,PL/SQL 只是壳。把 JSON_TABLE 当成表、把路径当成列、把约束和索引当成刚需,才能避开绝大多数性能坑。


















