表函数必须声明为PIPELINED且返回嵌套表或varray类型,SQL中须用TABLE()包装调用;PIPE ROW边计算边推送,禁止后续DML,异常不撤回已推送行。

Oracle PL/SQL 表函数(Table Function)不是普通函数,它返回的是**可被 SQL 直接查询的行集**,本质是把 PL/SQL 的逻辑结果“暴露”给 SQL 引擎。用错地方或忽略限制,轻则报 ORA-06553: PLS-306,重则查询卡死或返回空结果。
表函数必须带 PIPELINED 且返回集合类型
普通函数返回单个值,表函数必须声明为 PIPELINED,且返回类型只能是预定义或用户定义的嵌套表(TABLE OF)或 varray 类型。不加 PIPELINED,SQL 中调用会直接报错 ORA-06553: PLS-306;返回 VARCHAR2 或 NUMBER 等标量类型也不合法。
- 正确示例:返回自定义嵌套表类型
t_numberstab CREATE OR REPLACE TYPE t_numberstab AS TABLE OF NUMBER;
CREATE OR REPLACE FUNCTION gen_numbers(p_count NUMBER) RETURN t_numberstab PIPELINED IS BEGIN FOR i IN 1..p_count LOOP PIPE ROW(i); -- 每次输出一行 END LOOP; RETURN; -- 必须有 RETURN,即使无值 END;- 错误写法:
RETURN NUMBER、漏掉PIPELINED、或用RETURN返回具体数值
SQL 中必须用 TABLE() 包裹才能查询
表函数不能像普通函数那样直接出现在 SELECT 列表里,必须通过 TABLE() 函数包装,并在 FROM 子句中使用——这是最常被忽略的语法硬性要求。
- ✅ 正确调用:
SELECT * FROM TABLE(gen_numbers(5)) - ❌ 错误调用:
SELECT gen_numbers(5) FROM dual(报ORA-00932) - ❌ 错误调用:
SELECT * FROM gen_numbers(5)(报ORA-00942:表或视图不存在) - 支持传参,包括绑定变量:
SELECT * FROM TABLE(gen_numbers(:n)) - 可与其他表
JOIN,但注意性能:PL/SQL 执行是逐行PIPE ROW,大数据量时不如纯 SQL 高效
PIPE ROW 与内存、异常处理的边界很关键
PIPE ROW 不是缓存全部结果再返回,而是边计算边推送,这对大结果集友好,但也带来两个现实约束:
- 一旦开始
PIPE ROW,后续不能再执行 DML(如INSERT/UPDATE),否则报ORA-14551(无法在查询中执行 DML) - 异常发生时,已
PIPE ROW的数据仍会返回给 SQL 层,EXCEPTION块里RETURN不会撤回已推送的行 - 不支持在
PIPELINED函数里开游标并用FOR UPDATE,也不能调用自治事务函数 - 若需中间状态(如计数、临时聚合),必须用局部变量维护,但要注意并发调用时的隔离性——每个函数调用实例有独立变量空间
真正难的不是写出来,而是想清楚:这个逻辑是否真的需要表函数?比如只是做条件映射,DECODE 或 CASE WHEN 更轻量;如果只是查几张表拼结果,视图或 WITH 子句更合适。表函数的价值在于封装不可下推的 PL/SQL 逻辑(如调用外部 API、复杂递归、动态解析 JSON),而不是替代 SQL 基本能力。


















