不支持。Oracle 12c原生不识别LATERAL关键字,直接使用会报错;其等价功能需通过CROSS JOIN TABLE(...)调用管道函数实现,且函数参数须引用左表列。

Oracle 12c 是否支持 LATERAL 关键字?
不支持。Oracle 12c(包括 12.1 和 12.2)的 SQL 引擎**原生不识别 LATERAL 关键字**,直接写会报错 ORA-00905: missing keyword 或 ORA-00920: invalid relational operator。这是很多从 PostgreSQL 或 SQL Server 迁移过来的开发者踩的第一个坑——误以为 Oracle 12c 已具备该语法能力。
那为什么资料里说“Oracle 12c 支持 LATERAL”?
这类说法通常混淆了两个概念:
- Oracle 12c 引入了
LATERAL的语义等价能力,但**通过CROSS JOIN TABLE(...)+ 表函数实现**,而非标准 SQL 的LATERAL关键字; - 真正支持
LATERAL关键字是 Oracle 12.2 的一个补丁(如 12.2.0.1.180717)之后才部分启用,且需显式开启隐含参数(不推荐生产使用),官方文档从未将其列为正式特性; - 所有稳定、可移植的写法,都应基于
TABLE()函数调用 + 隐式相关性(即左表列在函数参数中被引用)来模拟 LATERAL 行为。
如何正确内联调用 PL/SQL 表函数(如 fn_split)?
必须用 CROSS JOIN TABLE(...) 语法,并确保函数参数能引用左侧表的列。Oracle 会自动将这种写法优化为“每行驱动一次函数调用”,效果等同于 LATERAL。
例如,对 T_DBATest 表中每个 c_description 字段做拆分:
SELECT t1.id, t1.c_name, t1.c_description, t2.column_value FROM T_DBATest t1 CROSS JOIN TABLE(fn_split(t1.c_description, '-')) t2;
关键点:
-
fn_split必须是 pipelined 函数,返回类型为预先定义的集合类型(如tabletype); - 函数调用写在
TABLE()内部,且参数t1.c_description明确依赖左表别名t1; - 不能写成子查询形式:
(SELECT * FROM TABLE(fn_split(...)))—— 这会失去行级关联,变成对固定字符串的单次调用; - 若需保留无匹配项的左行(类似
OUTER APPLY),改用LEFT JOIN ... ON 1=1+WHERE ... IS NOT NULL模拟,或改用OUTER JOIN加条件过滤(Oracle 不支持OUTER APPLY语法)。
性能与兼容性要注意什么?
这种写法在 Oracle 12c 中是安全、高效且广泛使用的,但有几个实际限制容易被忽略:
- 函数体内部不能有 DML(如
INSERT/UPDATE),否则报ORA-14551: cannot perform a DML operation inside a query; - 若
fn_split输入CLOB,而字段值超 32767 字节,SUBSTR在 PL/SQL 中会截断——建议在函数内加DBMS_LOB.SUBSTR替代; - Oracle 12c 对
TABLE()右侧表达式的谓词下推能力有限,避免在WHERE子句中对t2.column_value做复杂计算后再过滤,应尽量让过滤条件落在函数输入端(如先WHERE t1.c_description IS NOT NULL); - 如果升级到 Oracle 19c 或 21c,可考虑改用原生
JSON_TABLE解析(对 JSON 格式字符串)或正则REGEXP_SUBSTR+CONNECT BY,它们在某些场景下比自定义 pipelined 函数更快且无需创建类型。
最常被漏掉的是函数参数的空值处理:当 t1.c_description 为 NULL 时,fn_split(NULL, '-') 默认返回空集,导致整行被 CROSS JOIN 过滤掉——如果你需要保留这些空描述的记录,得在函数里显式处理 NULL 输入并返回单行 NULL,或在外层用 LEFT JOIN 拆解逻辑。











