oracle 21c支持json类型参数,19c不支持;21c中必须声明为json类型才能启用二进制解析和函数索引,否则json_value等返回null;json_table在21c可复用已解析结构,19c需重复解析;sql_macro仅21c支持,用于静态sql内联条件片段。

JSON 类型参数支持是核心区别:Oracle 19c 不支持原生 JSON 参数类型,21c 支持且必须用它才能启用二进制解析和函数索引。
存储过程参数能否声明为 JSON 类型?
Oracle 19c 不识别 JSON 作为过程参数类型,定义时会报错 ORA-00902: invalid datatype。所有 JSON 处理只能靠 CLOB 或 VARCHAR2 入参,再用 JSON_VALUE、JSON_EXISTS 等函数解析——但此时 Oracle 把输入当普通字符串,不校验合法性,也不走二进制解析路径。
Oracle 21c 允许且要求:参数必须声明为 json_input JSON。否则即使传入合法 JSON 字符串,JSON_EXISTS 仍返回 FALSE,JSON_VALUE 返回 NULL,且无法利用 JSON 列上的函数索引。
- ✅ 正确(21c only):
CREATE PROCEDURE parse_order(json_input JSON) IS ... - ❌ 19c 中写这个直接编译失败;21c 中写成
json_input CLOB虽能编译,但失去所有 JSON 原生优势
JSON_TABLE 在两个版本中的可用性与行为差异
JSON_TABLE 从 Oracle 12.2 就已引入,19c 和 21c 都支持,但 21c 对其做了关键优化:当输入是 JSON 类型参数时,JSON_TABLE 可复用已解析的二进制结构,避免重复解析整段 JSON;而 19c 下无论怎么写,都得从头解析字符串。
实际影响明显:同一段含 5 个字段的 JSON,用 5 个 JSON_VALUE 提取在 19c 中是 5 次全量解析;在 21c 中若先转成 JSON 类型再喂给 JSON_TABLE,则只有 1 次解析开销。
- 19c 必须接受:多字段提取 = 多次
JSON_VALUE+ 手动拼接或游标循环 - 21c 推荐:统一用
JSON_TABLE,尤其当字段跨层级(如$.user.name和$[0].items.price) - 注意:
JSON_TABLE的COLUMNS子句中路径写法一致,但 21c 支持更严格的路径语法校验(如自动拒绝未加引号的中文键名)
SQL 宏(SQL_MACRO)是否可用于存储过程?
SQL_MACRO 是 Oracle 21c 新增特性,19c 完全不支持。它不能直接“放在”存储过程中执行,而是定义后被静态 SQL 引用——所以只适用于存储过程里写的查询语句,不适用于 DML 或 PL/SQL 控制流。
典型误用:想用宏动态替换表名或列名。这在两个版本都会失败,但错误时机不同:
- 19c:根本无法创建带
SQL_MACRO的函数,CREATE FUNCTION ... SQL_MACRO直接报ORA-00905: missing keyword - 21c:能创建,但调用时若试图用参数代入对象名(如
FROM p_table_name),编译时报ORA-64625: invalid identifier in sql macro
真正可用场景(21c only):封装固定表结构下的条件片段,例如 filter_by_date_range(p_start DATE, p_end DATE) 返回 AND created_at BETWEEN p_start AND p_end,然后在存储过程的 SELECT 里用 && filter_by_date_range(...) 内联展开。
不可变表(IMMUTABLE TABLE)相关语法是否兼容?
IMMUTABLE 表是 19c 引入、21c 延续的特性,语法基本一致。但注意两点:
- 19c 要求
compatible至少设为'19.11.0';21c 要求至少'21.3.0',否则CREATE IMMUTABLE TABLE报ORA-02000: missing IMMUTABLE keyword类错误 -
NO DELETE UNTIL ... DAYS AFTER INSERT的最小天数限制在两个版本都是 16 天,但 21c 新增了LOCKED修饰符,一旦加了就不能用ALTER TABLE修改保留期 - 存储过程中对不可变表执行
DELETE或DROP,19c 和 21c 都会立即报错,不依赖触发器——这是 DDL 层强制约束
真正容易被忽略的是:不可变表的 NO DROP 和 NO DELETE 设置,在存储过程中无法绕过;哪怕用动态 SQL EXECUTE IMMEDIATE 也一样拦截,不是靠权限控制,而是内核级保护。











