2017-06-29 129 views
0

我有以下存儲過程:Oracle存儲過程 - 存儲查詢結果

CREATE OR REPLACE PROCEDURE SP 
(
    query IN VARCHAR2(200), 
    CURSOR_ OUT SYS_REFCURSOR 
) 
AS 
    row_ PROCESSED_DATA_OBJECT; 
    processed PROCESSED_DATA_TABLE; 
BEGIN 

     ..... 

END; 

CREATE TYPE processed_data_obj AS OBJECT(
    id INTEGER, 
    value FLOAT 
); 
/

CREATE OR REPLACE TYPE processed_data_table AS TABLE OF processed_data_obj; 
/

我打電話傳遞查詢作爲輸入參數要執行的存儲過程。 查詢是類似的東西:

SELECT A,B FROM TABLE WHERE 

,其中A,B和表是不固定的(在Java程序執行期間運行時所定義的),所以我不知道提前它們的值。

我怎樣才能獲取/存儲每個返回的行在我的結構?

processed PROCESSED_DATA_TABLE; 

由於

+0

從我的理解你的問題,你將不得不求助於動態SQL。壞消息是,你將無法使用本地動態SQL(通過EXECUTE IMMEDIATE),你必須使用DBMS_SQL包(調查)來使用稱爲方法4的東西。如果確實如此,那麼這將不是一件容易的事。祝你好運 –

+0

「A,B和TABLE不固定」。總是會有兩列,一個整數和一個數字,這是否是固定的?或者投影的列數可能更多或更少? – APC

+0

@APC總是會有2列。列和表的名稱可能不同 – Fab

回答

1

這是可以處理動態生成的查詢轉換爲用戶定義的類型的一種方法。請注意,爲了使其工作,查詢的結構(列)必須與您的類型(屬性)的數據類型結構相匹配,否則您會遇到麻煩。

CREATE TYPE processed_data_obj AS OBJECT(
    ID INTEGER, 
    VALUE FLOAT, 

    constructor FUNCTION processed_data_obj RETURN self AS result 
); 
/
CREATE OR REPLACE TYPE BODY processed_data_obj IS 
    constructor FUNCTION processed_data_obj RETURN self AS result IS 
    BEGIN 
     RETURN; 
    END; 
END; 
/
CREATE OR REPLACE TYPE processed_data_table AS TABLE OF processed_data_obj; 
/
CREATE OR REPLACE PROCEDURE sp (
    p_query IN VARCHAR2 
) AS 
    cursor_  sys_refcursor; 
    processed  processed_data_table := processed_data_table(); 
BEGIN 
    OPEN cursor_ FOR p_query; 
    loop 
     processed.EXTEND; 
     processed(processed.count) := processed_data_obj(); 
     fetch cursor_ INTO processed(processed.count).ID, processed(processed.count).VALUE; 
     exit WHEN cursor_%notfound; 
     dbms_output.put_line(processed(processed.count).ID||' '||processed(processed.count).VALUE);-- at this point do as you please with your data. 
    END loop; 
    CLOSE cursor_; -- always close cursor ;) 
    processed.TRIM; -- or processed.DELETE(processed.count); 
END sp; 

我發現,原來,你是把CURSOR_作爲輸出參數在存儲過程中,如果仍然是你的目標,你可以創建你的程序爲:

CREATE OR REPLACE PROCEDURE sp (
    p_query IN VARCHAR2, 
    cursor_ out sys_refcursor 
) AS 
    processed  processed_data_table := processed_data_table(); 
BEGIN 
    OPEN cursor_ FOR p_query; 
    loop 
     processed.EXTEND; 
     processed(processed.count) := processed_data_obj(); 
     fetch cursor_ INTO processed(processed.count).ID, processed(processed.count).VALUE; 
     exit WHEN cursor_%notfound; 
     dbms_output.put_line(processed(processed.count).ID||' '||processed(processed.count).VALUE);-- at this point do as you please with your data. 
    END loop; 
    -- cursor remains open 
    processed.TRIM; -- or processed.DELETE(processed.count); 
END sp; 

在這種情況下,只是有意識地處理你的光標,並且在你完成之後總是關閉它。

+0

我試過你的代碼,這是我正在尋找的。只是一個問題:'SELECT * FROM TABLE(processed)'給了我最後一個記錄等於'null'。在執行'processed.EXTEND'和'processed ...:= ...'之前,我在光標狀態上添加了一個'if'嗎? – Fab

+1

很高興聽到它爲你工作。關於調節'EXTEND',很難知道什麼時候停止擴展集合,因爲知道等待'FETCH'到達'CURSOR_'的EOF的唯一途徑,但是因爲集合需要是擴展/實例化以接收提取的值(否則你會引發一個'Reference to Uninitialized Composite'異常)這將是一個問題,我寧願推薦發佈'processed.TRIM'或者'processed.DELETE(processed.count)''指令在循環結束後刪除集合的最後一個元素。我已經更新了我的答案,以演示 –

+1

當然,另一種瞭解查詢期望有多少元素的方法可能是通過局部變量(而不是集合)遍歷它,或者通過遊標的「rowcount」屬性或本地計數器,然後就像您所說的那樣,在收集進入收集週期內調整收集的擴展。祝你好運。 –