PIPELINED函数必须声明RETURN TABLE OF类型,使用PIPE ROW()逐行输出,禁止RETURN、COMMIT、DDL等操作,调用时须用TABLE()包装。
PIPELINED 函数必须配 RETURN TABLE OF 类型
pl/sql 流水线函数不是“返回一个集合”,而是“持续输出行”,所以声明时不能写 return varchar2 或 return sys_refcursor。oracle 要求明确指定管道输出的行结构,也就是 return table of xxx_type。
常见错误现象:PLS-00653: aggregate/table functions are not allowed in this context,通常是因为调用方没用 TABLE() 包裹,或函数本身没声明对的返回类型。
- 先定义对象类型:
CREATE OR REPLACE TYPE t_row AS OBJECT (id NUMBER, name VARCHAR2(100)) - 再定义表类型:
CREATE OR REPLACE TYPE t_tab AS TABLE OF t_row - 函数签名必须是:
FUNCTION f_pipe RETURN t_tab PIPELINED
PIPELINED 体内只能用 PIPE ROW(),不能用 RETURN
流水线函数的执行逻辑是“边算边吐”,PIPE ROW() 是唯一合法的输出动作;一旦遇到 RETURN(哪怕在循环外),函数就立即终止,后续行不会发出——这和普通函数完全不同。
使用场景:适合处理大结果集但不想全量构造集合对象(比如避免 COLLECT 内存暴涨),或需要实时响应上游查询(如嵌套在 SELECT * FROM TABLE(f_pipe()) 中)。
-
PIPE ROW(t_row(1, 'a'))正确,每调一次就向数据流推送一行 - 不能写
RETURN t_tab(...),否则报PLS-00372: In a pipelined function, 'RETURN' must be followed by a table expression - 也不能在
EXCEPTION块里PIPE ROW(),Oracle 不允许异常路径中输出行
调用 PIPELINED 函数必须加 TABLE() 包装
Oracle 不允许直接把流水线函数当表名用,必须显式套一层 TABLE(),否则报 ORA-22905: cannot access rows from a non-nested table item。
参数差异:如果函数带参数,TABLE() 内部写法和普通函数调用一致,但括号位置容易错:
- 正确:
SELECT * FROM TABLE(f_pipe(100)) - 错误:
SELECT * FROM TABLE(f_pipe)(100)(把参数甩到外面了) - 错误:
SELECT * FROM f_pipe(100)(缺TABLE(),语法不通过)
性能影响:TABLE() 是优化器识别流水线的关键标记,缺了它,整个查询可能退化成物化中间结果,失去流式优势。
PIPELINED 函数里不能用 COMMIT / ROLLBACK / DDL
这是硬性限制,不是建议。只要函数体里出现 COMMIT、ROLLBACK、CREATE TABLE 等语句,编译直接失败,报 PLS-00703: multiple instances of a given type are not allowed in a single scope 或更常见的 ORA-14551: cannot perform a DML operation inside a query。
原因很简单:流水线函数可能被 SQL 引擎反复调用、中断、重入,事务状态无法可靠维护;DDL 更会破坏语句级一致性。
- 如果真要改数据,得把 DML 拆出去,用普通过程做,PIPELINED 只负责查和转
- 想记录日志?别用
INSERT INTO log_table,改用DBMS_OUTPUT.PUT_LINE(仅调试)或自治事务过程封装 - 注意:即使函数标了
AUTONOMOUS_TRANSACTION,也不能在 PIPELINED 里用 COMMIT —— Oracle 明确禁止
最常被忽略的是隐式 DML:比如调用了另一个含 COMMIT 的过程,或者触发器里有提交逻辑。这种链路式污染很难一眼发现。










