我可以将显式游标传递给函数/过程以在FOR循环中使用吗?

时间:2012-05-17 04:23:49

标签: plsql

我有一个程序对游标返回的所有记录执行一些计算。看起来有点像这样:

PROCEDURE do_calc(id table.id_column%TYPE)
IS
  CURSOR c IS
    SELECT col1, col2, col3
      FROM table
     WHERE ...;
BEGIN
  FOR r IN c LOOP
    -- do some complicated calculations using r.col1, r.col2, r.col3 etc.
  END LOOP;
END;

现在我需要对来自不同表的不同记录集执行完全相同的计算。但是,它们具有与上述示例中相同的“形状”。

是否可以编写如下所示的过程:

PROCEDURE do_calc2(c some_cursor_type)
IS
BEGIN
  FOR r IN c LOOP
    -- do the calc, knowing we have r.col1, r.col2, r.col3, etc.
  END LOOP;
END;

我知道SYS_REFCURSOR,但我想知道是否可以使用更方便的FOR ... LOOP语法和隐式记录类型。

4 个答案:

答案 0 :(得分:11)

创建一个包。

将光标声明为包变量。

使用%rowtype设置功能参数类型。

create or replace package test is
  cursor c is select 1 as one, 2 as two from dual;

  procedure test1;
  function test2(test_record c%ROWTYPE) return number;

end test;


create or replace package body test is
  procedure test1 is    
  begin
    for r in c loop      
      dbms_output.put_line(test2(r));
    end loop;
  end;

  function test2(test_record c%ROWTYPE) return number is
    l_summ number;
  begin
    l_summ := test_record.one + test_record.two;
    return l_summ;
  end;
end test;

答案 1 :(得分:2)

我有一个类似的问题,我有两个游标需要以相同的方式处理,所以这就是我想出来的。

DECLARE
   --Define our own rowType
   TYPE employeeRowType IS RECORD (
      f_name           VARCHAR2(30),
      l_name            VARCHAR2(30));
   --Define our ref cursor type
   --If we didn't need our own rowType, we could have this: RETURN employees%ROWTYPE
   TYPE empcurtyp IS REF CURSOR RETURN employeeRowType;

   --Processes the cursors
   PROCEDURE process_emp_cv (emp_cv IN empcurtyp) IS
      person employeeRowType;
   BEGIN
      LOOP
         FETCH emp_cv INTO person;
         EXIT WHEN emp_cv%NOTFOUND;
         DBMS_OUTPUT.PUT_LINE('Name = ' || person.f_name ||
                          ' ' || person.l_name);
      END LOOP;
   END;

   --Defines the cursors
   PROCEDURE mainProcedure IS
    emp empcurtyp;
   BEGIN
      OPEN emp FOR SELECT first_name, last_name FROM employees WHERE salary > 50000;
      process_emp_cv(emp);
      CLOSE emp;

      OPEN emp FOR SELECT first_name, last_name FROM kuren WHERE first_name LIKE 'J%';
      process_emp_cv(emp);
      CLOSE emp;
   END;

BEGIN
  mainProcedure;
END;
/

如果您想批量收集游标,也可以使用此功能。您只需要更改辅助程序process_emp_cv;其余的可以保持不变。

使用BULK COLLECT

 --Processes the cursors
   PROCEDURE process_emp_cv (emp_cv IN empcurtyp) IS
      TYPE t_employeeRowTable IS TABLE OF employeeRowType;
      employeeTable   t_employeeRowTable;
   BEGIN
      LOOP
         FETCH emp_cv BULK COLLECT INTO employeeTable LIMIT 50;
         FOR indx IN 1 .. employeeTable.Count
         LOOP
            DBMS_OUTPUT.PUT_LINE('Name = ' || employeeTable(indx).f_name ||
                          ' ' || employeeTable(indx).l_name);
         END LOOP;
         EXIT WHEN emp_cv%NOTFOUND;
      END LOOP;
   END;

答案 2 :(得分:0)

试试这个,Usong ref cursor。

    declare
    type c is ref cursor;
    c2 c;
    type rec is record(
    id number,
    name varchar(20)
    );
    r rec;
    procedure p1(c1 in out c,r1 in out rec)is begin

    loop
    fetch c1 into r1;
    exit when c1%notfound;
    dbms_output.put_line(r1.id || ' ' ||r1.name);
    end loop;
    end;
    begin
    open c2 for select id, name from student;
    p1(c2,r);
    end;

答案 3 :(得分:-1)

是的,您可以将Cursor明确地用于过程和函数,因为该游标需要声明为包作为变量