json_table是oracle 12c+解析复杂json的首选方式,必须在from子句中作为派生表使用,不可在select或where中直接调用;处理嵌套数组需用nested path(12.2+)或双层json_table,pl/sql中须通过select into调用,不能直接赋值。
oracle 12c 及以上版本中,json_table 是解析复杂 json 的首选方式;pl/sql 本身不提供原生 json 解析器,所谓“pl/sql 解析”本质是调用 sql 引擎执行 json_table、json_value 等函数——直接在 pl/sql 表达式里写 json_value(my_json, '$.x') 会报错。
JSON_TABLE 必须出现在 FROM 子句,不能当普通函数用
这是最常踩的坑:把 JSON_TABLE 当成 SUBSTR 或 TO_NUMBER 那样在 SELECT 列表或 WHERE 条件里直接调用。它只能作为数据源出现在 FROM 或 LATERAL 关联中。
- 错误写法:
SELECT id, JSON_TABLE(json_col, '$' COLUMNS (name VARCHAR2(50) PATH '$.name')) FROM t—— 语法报错 ORA-00923 - 正确写法:
SELECT jt.name FROM t, JSON_TABLE(t.json_col, '$' COLUMNS (name VARCHAR2(50) PATH '$.name')) jt - 路径参数必须是表达式:支持列名(
json_col)、绑定变量(:json_str)、字面量('{"a":1}'),但不能是拼接结果(如'{"a":' || 1 || '}') - 嵌套数组需显式展开:对
{"orders":[{"id":1,"items":[{"sku":"A"}]}]},单层JSON_TABLE(..., '$.orders[*]' COLUMNS (...))只能取到 order.id,取不到 items.sku
处理多层嵌套数组必须用 NESTED PATH 或双层 JSON_TABLE
用 NESTED PATH 是 12.2+ 最清晰、性能更稳的做法;它避免了手动关联导致的笛卡尔积,也比在外层路径反复引用子数组更可靠。
- 错误写法:
JSON_TABLE(json_col, '$.orders[*]' COLUMNS (order_id NUMBER PATH '$.id', sku VARCHAR2(20) PATH '$.items[0].sku'))—— 只取第一个 item,且 items 为空时整行丢失 - 正确写法(NESTED):
JSON_TABLE(json_col, '$.orders[*]' COLUMNS (order_id NUMBER PATH '$.id', NESTED PATH '$.items[*]' COLUMNS (sku VARCHAR2(20) PATH '$.sku'))) - 等效写法(双层):
SELECT jt1.order_id, jt2.sku FROM JSON_TABLE(...) jt1, JSON_TABLE(jt1.items, '$[*]' COLUMNS (sku VARCHAR2(20) PATH '$.sku')) jt2 - 空数组/NULL 行为可控:加
NULL ON EMPTY可让缺失items的 order 仍保留一行(sku为 NULL)
PL/SQL 块里调用 JSON_TABLE 要走 SELECT INTO,不能直接赋值
PL/SQL 不支持在变量赋值语句中直接调用 SQL 函数;所有 JSON 解析逻辑必须包裹在 SELECT ... INTO 或游标中,由 SQL 引擎执行。
- 错误写法:
DECLARE l_json CLOB := '{"x":1}'; l_val NUMBER := JSON_VALUE(l_json, '$.x');—— 编译失败:PLS-00222 - 正确写法:
DECLARE l_json CLOB := '{"x":1}'; l_val NUMBER; BEGIN SELECT JSON_VALUE(l_json, '$.x') INTO l_val FROM DUAL; END; - 批量解析推荐用 BULK COLLECT:
SELECT jt.id, jt.name BULK COLLECT INTO l_ids, l_names FROM JSON_TABLE(:json_str, '$[*]' COLUMNS (id NUMBER PATH '$.id', name VARCHAR2(100) PATH '$.name')) jt; - 类型不匹配会报错:比如 JSON 里
"price": 99.95,但定义成price NUMBER(3)→ ORA-40473;定义成VARCHAR2(5)→ 可能截断为"99.95"或"99.9"(取决于实际精度)
真正难的不是写对语法,而是确保输入 JSON 合法(IS JSON 校验)、路径与结构严格匹配、以及空值/缺失字段的容错策略——这些在动态接口场景里往往比语法更早暴露问题。











