循环从具有许多表的过程返回的游标

时间:2013-09-10 20:56:51

标签: sql oracle stored-procedures

我正在使用一个我没写过的存储过程,它很长并且包含许多列和连接。该过程返回一个游标,应用程序服务器(.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',然后打开了一个带有查询到该表的游标,以进行循环。过程何时将游标返回到具有多个表的复杂查询?

2 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:4)

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

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;

此外,如果您只需要打印引用游标的内容,您可以在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