普通函数不能直接返回多行,因其设计仅支持单个标量返回值;若需返回多行,必须使用pipelined函数配合自定义对象类型和表类型,并通过pipe row()逐行推送,调用时须包裹table()。
oracle函数默认只能返回单值,要返回多行数据,必须用 pipelined 函数 + 自定义集合类型,不能靠普通函数或存储过程直接“return 多行”。
为什么普通函数不能直接返回多行?
Oracle 的标准函数(FUNCTION)设计上只允许一个标量返回值,比如 NUMBER、VARCHAR2 或自定义对象实例。即使你写个循环查出 100 行,也没法在 RETURN 语句里一股脑塞进去——语法报错,常见错误是:
-
PLS-00382: expression is of wrong type(返回类型和声明不匹配) -
PLS-00653: aggregate/table functions not allowed in this context(试图在非集合上下文用集合)
根本原因:函数签名里没声明“我返回的是表结构”,数据库不知道怎么解析结果。
PIPELINED 函数必须配对象类型和表类型
管道函数不是“开箱即用”的,它依赖两层类型定义:
- 先建一个
OBJECT类型,描述每行的字段名和类型,例如:CREATE OR REPLACE TYPE emp_row AS OBJECT (empno NUMBER, ename VARCHAR2(10)) - 再建一个
TABLE OF该对象的嵌套表类型:CREATE OR REPLACE TYPE emp_table AS TABLE OF emp_row
注意:emp_table 必须作为函数的 RETURN 类型出现,且后面紧跟 PIPELINED 关键字。漏掉任意一层,调用时会报 ORA-00902: invalid datatype 或无法识别 PIPE ROW。
PIPE ROW() 不是“输出”,而是“推入流水线”
PIPE ROW() 的作用不是打印或缓存,而是把构造好的对象实例立刻推给调用方(比如 SELECT * FROM TABLE(...)),之后函数继续执行下一轮循环。关键点:
- 每次
PIPE ROW(x)只能传一个对象实例,不能传数组、游标或记录变量(%ROWTYPE) - 函数体内可以有多个
PIPE ROW(),但最后必须以无参数的RETURN;结尾(不是RETURN xxx;) - 如果循环里没触发
PIPE ROW()(比如 WHERE 条件全不满足),函数就返回空结果集,不会报错
示例片段:
FOR r IN (SELECT empno, ename FROM emp WHERE deptno = p_deptno) LOOP PIPE ROW(emp_row(r.empno, r.ename)); -- 构造对象并推送 END LOOP; RETURN; -- 必须写,且不能带值
调用时必须套 TABLE(),不能直接 SELECT 函数名
管道函数返回的是集合类型,不是结果集。直接写 SELECT my_pipelined_func(10) FROM dual 会得到一个 <collection></collection> 字符串,毫无意义。正确用法只有两种:
-
SELECT * FROM TABLE(my_pipelined_func(10))—— 最常用,当物理表一样查 -
SELECT col1, col2 FROM TABLE(my_pipelined_func(10)) t—— 支持别名和字段投影
容易忽略的细节:TABLE() 是 SQL 层语法,不能在 PL/SQL 块里直接赋值给集合变量(如 v_tab := my_pipelined_func(10)),那会触发类型不匹配。真要赋值,得用普通集合函数(非 PIPELINED)。











