1

我正在使用一个我没有编写的存储过程,它很长并且包含许多列和连接。该过程返回一个游标,应用程序服务器(.NET,顺便说一下)拾取并遍历该游标。

我正在尝试使用 SQLPlus 和 PL/SQL 拦截光标,但我很难弄清楚如何设置脚本。这是我到目前为止所拥有的:

DECLARE
    cur sys_refcursor;
BEGIN
  adv_schema.report_proc('CAL','01-JAN-2011','01-JAN-2012','Y',cur);
  OPEN cur FOR --??????
  LOOP
    FETCH cur INTO column1, column2;
    EXIT WHEN cur%NOTFOUND;
    DBMS_OUTPUT.Put_Line ('First Name: '||column1||' Last Name: '||column2);
  END LOOP;
END;

/

我在 OPEN 语句中放了什么?我所见过的所有关于如何执行此操作的示例都是过于简化的示例,其中在 PL/SQL 块中创建了一些表“t”,然后打开一个游标并对该表进行查询,以进行循环。当一个过程将游标返回到具有多个表的复杂查询时会怎样?

4

2 回答 2

5

假设report_proc程序正在返回游标(即第四个参数定义为OUT SYS_REFCURSOR),则代码中不需要OPEN游标。该过程已经打开它。你只需要从中获取。

于 2013-09-10T21:04:00.880 回答
4

正如@Justin 已经提到的,不需要打开report_proc过程返回的游标,您只需要从该游标中获取。引用游标是弱游标(基本上是不返回类型的游标),为了从弱类型游标中获取,您需要知道要获取什么。当您知道游标返回什么类型时,您可以声明要获取的本地结构,如下所示:

DECLARE
  -- example of record 
  -- in your case you have to know exactly
  -- how many column and of which datatype your ref cursor returns
   type T_Record is record(
     column_1 number,
     column_2 number
   );
   l_record T_Record;
   cur sys_refcursor;
BEGIN
    adv_schema.report_proc('CAL','01-JAN-2011','01-JAN-2012','Y',cur);
    LOOP
       FETCH cur 
        INTO l_record;
        EXIT WHEN cur%NOTFOUND;
       DBMS_OUTPUT.Put_Line ('First Name: '||l_record.column1
                           ||' Last Name: '||l_record.column2);
    END LOOP;
END;

此外,如果您只需要打印ref 游标的内容,您可以在 SQL*Plus 中执行如下操作:

SQL> variable cur refcursor;

SQL> exec adv_schema.report_proc('CAL','01-JAN-2011','01-JAN-2012','Y', :cur);

然后使用print命令打印refcursor cur

SQL> print cur;

我是否需要获取游标返回的每一列,或者我可以获取一个子集,比如前三个。

不,您获取所有内容,您不能选择性地获取要获取的列。然而,这并非不可能,但它将涉及使用dbms_sql包,特别是dbms_sql.describe_columns过程来获取有关游标列的信息。

只是为了考虑,如果您知道游标中肯定存在特定列,则可以使用xmlsequence()函数来获取特定列,并在extract()函数中指定其名称:

SQL> declare
  2    type T_List is table of varchar2(123);
  3    l_names   T_List;
  4    l_ref_cur sys_refcursor;
  5  
  6  begin
  7    open l_ref_cur
  8     for select first_name, last_name
  9           from employees
 10          where rownum <= 5;
 11  
 12   SELECT t.extract('ROW/FIRST_NAME/text()').getstringval()
 13     bulk collect into l_names
 14     FROM table(xmlsequence(l_ref_cur)) t;
 15  
 16    for indx in l_names.first..l_names.last
 17    loop
 18      dbms_output.put_line(l_names(indx));
 19    end loop;
 20  end;
 21  /

结果:

Ellen
Sundar
Mozhe
David
Hermann
PL/SQL procedure successfully completed
于 2013-09-10T21:29:00.780 回答