2010-05-13 93 views
16

我試圖在返回一個表的包中創建一個函數。我希望在包中調用一次函數,但能夠多次重複使用它的數據。雖然我知道我在Oracle中創建臨時表,但我希望讓事情保持乾爽。創建一個返回表的Oracle函數

到目前爲止,這是我所:

頁眉:

CREATE OR REPLACE PACKAGE TEST AS 

    TYPE MEASURE_RECORD IS RECORD (
     L4_ID VARCHAR2(50), 
     L6_ID VARCHAR2(50), 
     L8_ID VARCHAR2(50), 
     YEAR NUMBER, 
     PERIOD NUMBER, 
     VALUE NUMBER 
    ); 

    TYPE MEASURE_TABLE IS TABLE OF MEASURE_RECORD; 

    FUNCTION GET_UPS(
     TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
     STARTING_DATE_IN DATE, 
     ENDING_DATE_IN DATE 
    ) RETURN MEASURE_TABLE; 

END TEST; 

身體:

CREATE OR REPLACE PACKAGE BODY TEST AS 

    FUNCTION GET_UPS (
    TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
    STARTING_DATE_IN DATE, 
    ENDING_DATE_IN DATE 
) RETURN MEASURE_TABLE IS 

    T MEASURE_TABLE; 

    BEGIN 

     SELECT ... 
     INTO T 
     FROM ... 

     ; 

    RETURN T; 

    END GET_UPS; 

END TEST; 

頭編譯,身體沒有。一個錯誤消息是「數值不夠」,這可能意味着我應該選擇MEASURE_RECORD而不是MEASURE_TABLE。

我錯過了什麼?

回答

27

我想你想要一個pipelined table function

事情是這樣的:

CREATE OR REPLACE PACKAGE test AS 

    TYPE measure_record IS RECORD(
     l4_id VARCHAR2(50), 
     l6_id VARCHAR2(50), 
     l8_id VARCHAR2(50), 
     year NUMBER, 
     period NUMBER, 
     VALUE NUMBER); 

    TYPE measure_table IS TABLE OF measure_record; 

    FUNCTION get_ups(foo NUMBER) 
     RETURN measure_table 
     PIPELINED; 
END; 

CREATE OR REPLACE PACKAGE BODY test AS 

    FUNCTION get_ups(foo number) 
     RETURN measure_table 
     PIPELINED IS 

     rec   measure_record; 

    BEGIN 
     SELECT 'foo', 'bar', 'baz', 2010, 5, 13 
      INTO rec 
      FROM DUAL; 

     -- you would usually have a cursor and a loop here 
     PIPE ROW (rec); 

     RETURN; 
    END get_ups; 
END; 

爲了簡單起見,我刪除您的參數並沒有實現功能的循環,但你可以看到的原則。

用法:

SELECT * 
    FROM table(test.get_ups(0)); 



L4_ID L6_ID L8_ID  YEAR  PERIOD  VALUE 
----- ----- ----- ---------- ---------- ---------- 
foo bar baz   2010   5   13 
1 row selected. 
+0

我假設使用遊標將比使用臨時表更耗費資源(即更慢)。我對麼? 我需要將這個函數的結果分組。這會改變你的建議嗎? – craig 2010-05-13 23:37:36

+0

關於遊標,是的,我相信它們對性能不是很好,所以它可能會像Tony提到的那樣進行BULK COLLECT更快,然後遍歷數組。這取決於你正在處理的行數和其他性能方面的考慮。至於對結果進行分組,我不確定,但在任何情況下,臨時表似乎都可能比流水線函數更有效。我會建議更多的研究(或者更好的是,試驗)。我會在http://asktom.oracle.com上提問。 – 2010-05-14 16:06:26

+0

請解釋downvote。 – 2014-09-16 07:48:23

3

要一次,你可以在SELECT換回整個表:

SELECT ... 
BULK COLLECT INTO T 
FROM ... 

這僅僅是一點效果都沒有過大的建議,因爲他們都在返回之前必須在記憶中積累;否則考慮Charles建議的流水線函數,或返回一個REF CURSOR。

+0

感謝您的洞察力。 – craig 2010-05-14 13:35:18

0
CREATE OR REPLACE PACKAGE BODY TEST AS 

    FUNCTION GET_UPS(
    TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
    STARTING_DATE_IN DATE, 
    ENDING_DATE_IN DATE 
    )RETURN MEASURE_TABLE IS 

    T MEASURE_TABLE; 

BEGIN 

    **SELECT MEASURE_RECORD(L4_ID , L6_ID ,L8_ID ,YEAR , 
      PERIOD,VALUE) BULK COLLECT INTO T 
    FROM ...** 

    ; 

    RETURN T; 

    END GET_UPS; 

END TEST; 
+0

調用此函數的語法是什麼? 'select * from TABLE(TEST.GET_UPS(...))'? – craig 2016-02-25 19:34:46

相關問題