2012-06-25 66 views
8

下面的W.r.t代码我不能将fetch-into-variable的类型声明为基本表的%ROWTYPE,因为SYS_REFCURSOR位于select连接两个表的选择上,并且还选择了对两个基础表的属性调用的几个函数;即我不能宣布为L_RECORD T%ROWTYPE如何声明一个弱类型的SYS_REFCURSOR变量的%ROWTYPE?

--- 
DECLARE 
    P_RS SYS_REFCURSOR; 
    L_RECORD P_RS%ROWTYPE; 
BEGIN 
    CAPITALEXTRACT(
    P_RS => P_RS 
); 
    OPEN P_RS; 
    LOOP 
     BEGIN 
     FETCH P_RS INTO L_RECORD; 
     EXIT WHEN P_RS%NOTFOUND; 
     ... 
     EXCEPTION 
     WHEN OTHERS THEN 
     ... 
     END; 
    END LOOP; 
    CLOSE P_RS; 
END; 
-------- 
CREATE or REPLACE PROCEDURE CAPITALEXTRACT 
(
    p_rs OUT SYS_REFCURSOR 
) AS 
BEGIN 
    OPEN p_rs for 
    select t.*,tminusone.*, f(t.cash), g(t.cash) FROM T t, TMINUSONE tminusone 
    where t.ticket=tminusone.ticket; 
END CAPITALEXTRACT; 

当然我不希望作为SYS_REFCURSOR返回与列来定义静态表R和再声明为L_RECORD R%ROWTYPE。

因此,问题: 如何声明一个弱类型的SYS_REFCURSOR变量的%ROWTYPE?

回答

14

简短的回答是,你不能。您需要为每个将返回的列定义一个变量。

DECLARE 
    P_RS SYS_REFCURSOR; 
    L_T_COL1 T.COL1%TYPE; 
    L_T_COL1 T.COL2%TYPE; 
    ... 

然后取入列的列表:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ; 

这是痛苦的,但管理,只要你知道你在裁判光标期待什么。在你的过程中使用T.*会使得这个过程变得脆弱,因为向表中添加一列会破坏代码,认为它知道它们有什么列和它们的顺序(如果表不是这样,不断构建 - 我已经看到不同环境下列排序不同的地方)。您可能希望确保只选择您真正关心的列,以避免必须为永远不会读取的内容定义变量。

从11g开始,您可以使用DBMS_SQL包将sys_refcursor转换为DBMS_SQL游标,并且您可以通过询问来确定列。正如你可以做什么的例子,这将打印出每一列的值,每一行,列名为:

DECLARE 
    P_RS SYS_REFCURSOR; 
    L_COLS NUMBER; 
    L_DESC DBMS_SQL.DESC_TAB; 
    L_CURS INTEGER; 
    L_VARCHAR VARCHAR2(4000); 
BEGIN 
    CAPITALEXTRACT(P_RS => P_RS); 
    L_CURS := DBMS_SQL.TO_CURSOR_NUMBER(P_RS); 
    DBMS_SQL.DESCRIBE_COLUMNS(C => L_CURS, COL_CNT => L_COLS, 
     DESC_T => L_DESC); 

    FOR i IN 1..L_COLS LOOP 
     DBMS_SQL.DEFINE_COLUMN(L_CURS, i, L_VARCHAR, 4000); 
    END LOOP; 

    WHILE DBMS_SQL.FETCH_ROWS(L_CURS) > 0 LOOP 
     FOR i IN 1..L_COLS LOOP 
      DBMS_SQL.COLUMN_VALUE(L_CURS, i, L_VARCHAR); 
      DBMS_OUTPUT.PUT_LINE('Row ' || DBMS_SQL.LAST_ROW_COUNT 
       || ': ' || l_desc(i).col_name 
       || ' = ' || L_VARCHAR); 
     END LOOP; 
    END LOOP; 

    DBMS_SQL.CLOSE_CURSOR(L_CURS); 
END; 
/

那是没多大实际用途,并且为了简洁,我把每个值作为字符串,因为我只是想要打印它。查看文档并搜索更多实际应用的示例。

如果你只是想从你的参考光标你可以数列,我想,围绕l_desc环和记录位置column_name是不管你有兴趣,作为数字变量;稍后您可以通过该变量引用该列,您通常会在游标循环中使用该名称。取决于你在处理数据。

但除非你期待不知道你要回来的列的顺序,这是不可能的,因为你似乎控制程序 - 假设你摆脱.* S的 - 你大概是多少最好减少返回的列到您需要的最小值,并且只是单独声明它们。

+0

好棒的人,我一直在寻找一年如何做到这一点,这解释了它最好的。注意:我不需要CAPITALEXTRACT(P_RS => P_RS);线。 (事实上​​它错了,不知道它做了什么,所以我注释掉了,然后我的pl/sql运行得很好) – armyofda12mnkeys

+0

@ armyofda12mnkeys - 很高兴它有帮助。 CAPITALEXTRACT是针对这个问题的一个特定功能,而不是解决方案的固有内容,所以不用担心。 –

相关问题