8

下面的 Wrt 代码我不能将 fetch-into-variable 的类型声明为基础表的 %ROWTYPE,因为 SYS_REFCURSOR 位于连接两个表的选择上,并且还选择了一些在基础两个表的属性上调用的函数;即我不能声明为 L_RECORD T%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 ?

4

1 回答 1

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, ... ;

只要您知道您在 ref 光标中的期望,这很痛苦但可以管理。但是,在您的过程中使用T.*会使这变得脆弱,因为向表中添加列会破坏认为它知道有哪些列以及它们的顺序的代码。(如果表不是,您也可以在环境之间破坏它始终如一地构建 - 我见过在不同环境中列排序不同的地方)。您可能希望确保只选择您真正关心的列,以避免为您永远不会阅读的内容定义变量。

从 11g 开始,您可以使用该DBMS_SQL包将您的光标转换sys_refcursorDBMS_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-您最好将返回的列减少到您需要的最低限度,只需单独声明它们。

于 2012-06-27T19:54:37.170 回答