在 PL/SQL 開發中,常需撰寫「回傳集合」的函數供 SQL 陳述式以 TABLE() 運算子查詢。本文以 EMP 表為例,示範三種回傳 t_test_table (集合型別) 的寫法,並說明各自優缺點與適用情境。
所有方法皆需先建立 Schema 層級 的物件型別與集合型別(不可在 PL/SQL 區塊內部宣告):
CREATE OR REPLACE TYPE t_test AS OBJECT (
empno NUMBER(4),
ename VARCHAR2(10),
job VARCHAR2(9),
sal NUMBER(7,2)
);
/
CREATE OR REPLACE TYPE t_test_table AS TABLE OF t_test;
/
關鍵點:欄位型別必須為 OBJECT,不能使用 RECORD;否則 SQL 引擎無法識別。
CREATE OR REPLACE FUNCTION f_test_array (v_deptno IN NUMBER DEFAULT NULL)
RETURN t_test_table IS
v_test t_test_table := t_test_table(); -- 初始化空集合
CURSOR cur IS
SELECT empno, ename, job, sal FROM emp WHERE deptno = v_deptno;
BEGIN
FOR c IN cur LOOP
v_test.EXTEND; -- 擴充一個元素
v_test(v_test.COUNT) := t_test(c.empno, c.ename, c.job, c.sal);
END LOOP;
RETURN v_test;
END;
/
特性:
EXTEND/COUNT)。CREATE OR REPLACE FUNCTION f_test_pipe (v_deptno IN NUMBER DEFAULT NULL)
RETURN t_test_table PIPELINED IS
CURSOR cur IS
SELECT empno, ename, job, sal FROM emp WHERE deptno = v_deptno;
BEGIN
FOR c IN cur LOOP
PIPE ROW (t_test(c.empno, c.ename, c.job, c.sal)); -- 直接輸出一列
END LOOP;
RETURN; -- 不需回傳集合變數
END;
/
特性:
PIPELINED + PIPE ROW 即可「串流」輸出,不需在記憶體中累積完整集合。COMMIT/ROLLBACK,且不支援平行查詢 (Parallel Query)。CREATE OR REPLACE FUNCTION f_test_collect (v_deptno IN NUMBER DEFAULT NULL)
RETURN t_test_table IS
v_test t_test_table;
BEGIN
SELECT t_test(empno, ename, job, sal) -- 必須先「物件化」投影
BULK COLLECT INTO v_test
FROM emp
WHERE deptno = v_deptno;
RETURN v_test;
END;
/
關鍵細節:
SELECT 清單必須寫成 t_test(empno, ename, job, sal),將多欄位「包裝」成單一物件;否則會噴 ORA-00947: not enough values (多欄位) 或 ORA-00932: inconsistent datatypes (單欄位)。DECLARE 區域型別時則不需此步驟,僅限 CREATE FUNCTION 回傳 Schema 型別時必要。三種函數皆可用相同語法測試:
SELECT * FROM TABLE(f_test_array(30));
SELECT * FROM TABLE(f_test_pipe(30));
SELECT * FROM TABLE(f_test_collect(30));

| 情境 | 推薦方法 | 理由 |
|---|---|---|
| 資料量 < 1 萬筆、邏輯單純 | BULK COLLECT | 程式碼最少、維護容易 |
| 資料量大、需串流處理、低記憶體 | PIPELINED | 逐列輸出、首筆快、不佔用大量 PGA |
| 需複雜條件判斷、動態決定是否輸出 | Array Extend | 彈性最高、可任意控制集合內容 |
掌握三種回傳集合的寫法,能依據業務需求在「開發效率」、「記憶體使用」與「回應時間」間取得最佳平衡。實務上若無特殊邏輯,優先考慮 BULK COLLECT;涉及大量資料轉換或 ETL 管線則首選 PIPELINED。