Oracle管道函數(Pipelined Table Function)簡介數組
1、概述:服務器
一、管道函數便是能夠返回行集合(可使嵌套表nestedtable或數組varray)的函數,咱們能夠像查詢物理表同樣查詢它或者將其賦值給集合變量。 二、管道函數爲並行執行,在普通的函數中使用dbms_output輸出的信息,須要在服務器執行完整個函數後一次性的返回給客戶端。若是須要在客戶端實時的輸出函數執行過程當中的一些信息,在oracle9i之後可使用管道函數(pipelinefunction)。 3 、關鍵字PIPELINED代表這是一個Oracle管道函數,oracle管道函數的返回值類型必須爲集合,在函數中,PIPEROW語句被用來返回該集合的單個元素,函數以一個空的RETURN語句結束,以代表它已經完成。 四、因爲管道函數的併發多管道流式設計以及實時返回查詢結果而去除了中間環節所以能夠帶來可觀的性能提高。
2、如何編寫管道函數:併發
例1:
[SQL] 純文本查看 複製代碼oracle
CREATE OR REPLACE PACKAGE pkg1 AS函數
TYPE numset_t IS TABLE NUMBER; FUNCTION f1(x NUMBER) RETURN numset_t PIPELINED;
END pkg1;oop
[SQL] 純文本查看 複製代碼
?性能
CREATE OR REPLACE PACKAGE BODY pkg1 AS設計
FUNCTION f1(x NUMBER) RETURN numset_t PIPELINED IS BEGIN FOR i IN 1..x LOOP PIPE ROW(i); END LOOP; RETURN; END;
END pkg1;code
運行:
[SQL] 純文本查看 複製代碼
?
1
SELECT * FROM TABLE(pkg1.f1(5));事務
結果:
[SQL] 純文本查看 複製代碼
?
1 2 3 4 5
3、管道函數用於數據轉換:
例2:
管道函數能夠和常規函數同樣接收任何參數,下面的管道函數中參數爲ref cursor。
[Shell] 純文本查看 複製代碼
?
CREATE OR REPLACE PACKAGE refcur_pkg IS
TYPE refcur_t IS REF CURSOR RETURN emp%ROWTYPE;
TYPE outrec_typ IS RECORD (
var_num NUMBER(6), var_char1 VARCHAR2(30), var_char2 VARCHAR2(30));
TYPE outrecset IS TABLE OF outrec_typ;
FUNCTION f_trans(p refcur_t)
RETURN outrecset PIPELINED;
END refcur_pkg;
[SQL] 純文本查看 複製代碼
CREATE OR REPLACE PACKAGE BODY refcur_pkg IS
FUNCTION f_trans(p refcur_t)
RETURN outrecset PIPELINED IS
out_rec outrec_typ; in_rec p%ROWTYPE;
BEGIN
LOOP
FETCH p INTO in_rec; EXIT WHEN p%NOTFOUND; -- first row out_rec.var_num := in_rec.empno; out_rec.var_char1 := in_rec.ename; out_rec.var_char2 := in_rec.mgr; PIPE ROW(out_rec); -- second row out_rec.var_num := in_rec.deptno; out_rec.var_char1 := in_rec.deptno; out_rec.var_char2 := in_rec.job; PIPE ROW(out_rec);
END LOOP;
CLOSE p;
RETURN;
END;
END refcur_pkg;
運行:
[SQL] 純文本查看 複製代碼
?
1
SELECT FROM TABLE(refcur_pkg.f_trans(CURSOR(SELECT FROM emp WHERE empno=7782)));
結果:
VAR_NUM VAR_CHAR1 VAR_CHAR2
7782 CLARK 7839 10 10 MANAGER
4、用法擴展:
一、表函數間傳遞數據:
[SQL] 純文本查看 複製代碼
?
1
SELECT FROM TABLE(f(CURSOR(SELECT FROM TABLE(g()))));
二、使用遊標變量接收管道函數返回的結果:
[SQL] 純文本查看 複製代碼
?
1
OPEN c FOR SELECT * FROM TABLE(f(...));
三、使用多個遊標變量入參: 例3:Oac_no_warn代碼
[SQL] 純文本查看 複製代碼
?
-- Define the ref cursor types
CREATE PACKAGE refcur_pkg IS
TYPE refcur_t1 IS REF CURSOR RETURN employees%ROWTYPE;
TYPE refcur_t2 IS REF CURSOR RETURN departments%ROWTYPE;
TYPE outrec_typ IS RECORD (
var_num NUMBER(6), var_char1 VARCHAR2(30), var_char2 VARCHAR2(30));
TYPE outrecset IS TABLE OF outrec_typ;
FUNCTION g_trans(p1 refcur_t1, p2 refcur_t2)
RETURN outrecset PIPELINED;
END refcur_pkg;
/
CREATE PACKAGE BODY refcur_pkg IS
FUNCTION g_trans(p1 refcur_t1, p2 refcur_t2)
RETURN outrecset PIPELINED IS out_rec outrec_typ; in_rec1 p1%ROWTYPE; in_rec2 p2%ROWTYPE;
BEGIN
LOOP
FETCH p2 INTO in_rec2; EXIT WHEN p2%NOTFOUND;
END LOOP;
CLOSE p2;
LOOP
FETCH p1 INTO in_rec1; EXIT WHEN p1%NOTFOUND; -- first row out_rec.var_num := in_rec1.employee_id; out_rec.var_char1 := in_rec1.first_name; out_rec.var_char2 := in_rec1.last_name; PIPE ROW(out_rec); -- second row out_rec.var_num := in_rec2.department_id; out_rec.var_char1 := in_rec2.department_name; out_rec.var_char2 := TO_CHAR(in_rec2.location_id); PIPE ROW(out_rec);
END LOOP;
CLOSE p1;
RETURN;
END;
END refcur_pkg;
/
-- SELECT query using the g_trans table function
SELECT * FROM TABLE(refcur_pkg.g_trans(
CURSOR(SELECT * FROM employees WHERE department_id = 60),
CURSOR(SELECT * FROM departments WHERE department_id = 60)));
四、管道函數做爲聚合函數使用:
例4:Oac_no_warn代碼
[SQL] 純文本查看 複製代碼
CREATE TABLE gradereport (student VARCHAR2(30), subject VARCHAR2(30),
weight NUMBER, grade NUMBER);
INSERT INTO gradereport VALUES('Mark', 'Physics', 4, 4);
INSERT INTO gradereport VALUES('Mark','Chemistry', 4, 3);
INSERT INTO gradereport VALUES('Mark','Maths', 3, 3);
INSERT INTO gradereport VALUES('Mark','Economics', 3, 4);
CREATE PACKAGE pkg_gpa IS
TYPE gpa IS TABLE OF NUMBER;
FUNCTION weighted_average(input_values SYS_REFCURSOR)
RETURN gpa PIPELINED;
END pkg_gpa;
/
CREATE PACKAGE BODY pkg_gpa IS
FUNCTION weighted_average(input_values SYS_REFCURSOR)
RETURN gpa PIPELINED IS
grade NUMBER;
total NUMBER := 0;
total_weight NUMBER := 0;
weight NUMBER := 0;
BEGIN
-- The function accepts a ref cursor and loops through all the input rows
LOOP
FETCH input_values INTO weight, grade; EXIT WHEN input_values%NOTFOUND;
-- Accumulate the weighted average
total_weight := total_weight + weight; total := total + grade*weight;
END LOOP;
PIPE ROW (total / total_weight);
RETURN; -- the function returns a single result
END;
END pkg_gpa;
/
-- the query result comes back as a nested table with a single row
-- COLUMN_VALUE is a keyword that returns the contents of a nested table
SELECT w.column_value "weighted result" FROM TABLE(
pkg_gpa.weighted_average(CURSOR(SELECT weight, grade FROM gradereport))) w;
五、在管道函數中進行DML操做,咱們使用自治事務使管道函數做爲獨立事務處理:
[SQL] 純文本查看 複製代碼
?
CREATE FUNCTION f(p SYS_REFCURSOR)
RETURN CollType PIPELINED IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
NULL;
END;
/
六、對管道函數進行DML操做:
實際上咱們沒法直接對管道函數進行DML操做,例如如下語句都會失敗:
[SQL] 純文本查看 複製代碼
?
UPDATE F(CURSOR(SELECT * FROM tab)) SET col = value;
INSERT INTO f(...) VALUES ('any', 'thing');
官方給出的方案是建立一個基於管道函數的VIEW,而後在這個VIEW上建立相應的instead of 觸發器。下面給出操做實例:
[SQL] 純文本查看 複製代碼
CREATE OR REPLACE VIEW V_F_TRANS AS
SELECT x.var_num, x.var_char1, x.var_char2
FROM TABLE(refcur_pkg.f_trans(CURSOR (SELECT *
FROM emp))) x;
[SQL] 純文本查看 複製代碼
?
CREATE OR REPLACE TRIGGER tri_f_trans INSTEAD OF INSERT ON v_f_trans FOR EACH ROW BEGIN dbms_output.put_line('Trigger of a pipelined funtion based view was on fire!'); END;