2017-06-29 128 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”属性或本地计数器,然后就像您所说的那样,在收集进入收集周期内调整收集的扩展。祝你好运。 –