Oracle:如何填充/插入行到Ref Cursor?

时间:2017-03-13 09:22:55

标签: oracle plsql sys-refcursor

真的需要有关Ref Cursor的帮助。我有一个存储过程GET_PERSONROLES具有参数类型引用游标。我只是想手动将这个引用游标傀儡,就像在refcursor中插入一行一样。 我可以通过循环将行插入refcursor吗? 提前谢谢。

该程序取决于此公开声明的类型:

create or replace package types 
as 
    type cursorTypePersonRole is ref cursor; 
end;

这是我的伪代码

create or replace PROCEDURE GET_PERSONROLES
( 
  P_CURSOR IN OUT types.cursorTypePersonRole
) AS
  REFCUR SYS_REFCURSOR; 
  TYPE REFTABLETYPE IS RECORD (
    IS_MANAGER_LEVEL1 VARCHAR2(1),
    IS_MANAGER_LEVEL2 VARCHAR2(1)
  );
  TYPE TABLETYPE IS TABLE OF REFTABLETYPE;
  PERSONROLES_TABLETYPE TABLETYPE; 
BEGIN
  --calls another stored proc to populate REFCUR with data without problem
  MY_STOREDPROC('12345', REFCUR);
  LOOP
    FETCH REFCUR BULK COLLECT INTO PERSONROLES_TABLETYPE;
    EXIT WHEN PERSONROLES_TABLETYPE.COUNT = 0;
    FOR indx IN 1 .. PERSONROLES_TABLETYPE.COUNT 
    LOOP
       -- I'm able to query perfectly the values of IS_MANAGER_LEVEL1 and IS_MANAGER_LEVEL 2
       -- I'm aware that the below codes are wrong
       -- However this means I wanted to insert these values to a row of the cursor if possible
       -- Do some logic to know what data will be assigned in the row.
       if PERSONROLES_TABLETYPE(indx).IS_MANAGER_LEVEL1 = 'Y' then
           P_CURSOR := <DO SOME LOGIC AND ASSIGN THE VALUE TO THE ROW>
       end if;
       if PERSONROLES_TABLETYPE(indx).IS_MANAGER_LEVEL2 = 'Y' then
           P_CURSOR := <DO SOME LOGIC AND ASSIGN THE VALUE TO THE ROW>
       end if;
    END LOOP;
  END LOOP;     
  CLOSE REFCUR;
END GET_PERSONROLES;

1 个答案:

答案 0 :(得分:3)

引用游标不是变量:它是指向结果集的指针,该结果集由读取它的行为消耗。结果集本身是不可变的。

不可变性是有道理的,因为它反映了Oracle强调读取一致性。

生成您想要的输出的最简单方法是创建SQL类型

   open P_CURSOR for 
       select IS_MANAGER_LEVEL1,
              IS_MANAGER_LEVEL2 
       from table ( PERSONROLES_TABLETYPE );

这将在12c中起作用;在早期版本中使用table()这样的调用,您可能需要将REFTABLETYPETABLETYPE声明为SQL类型(而不是PL / SQL)。

  

“确定现在编辑”

唉,你的要求仍然不明确。您没有给我们输出引用光标的结构或显示您想要进行的其他处理。

然而,鉴于你的问题的标题,让我们猜一下。所以:

create or replace PROCEDURE GET_PERSONROLES ( P_CURSOR IN OUT types.cursorTypePersonRole) AS
  REFCUR SYS_REFCURSOR; 
  TYPE REFTABLETYPE IS RECORD (IS_MANAGER_LEVEL1 VARCHAR2(1),
    IS_MANAGER_LEVEL2 VARCHAR2(1));
  TYPE TABLETYPE IS TABLE OF REFTABLETYPE;
  PERSONROLES_TABLETYPE TABLETYPE; 
  personrole_rec PersonRole%rowtype;
  type personrole_nt is table of PersonRole%rowtype;
  personroles_recs personrole_nt := new personrole_nt() ; 
BEGIN
    MY_STOREDPROC('12345', REFCUR);
    FETCH REFCUR BULK COLLECT INTO PERSONROLES_TABLETYPE;
    FOR indx IN 1 .. PERSONROLES_TABLETYPE.COUNT LOOP
       /* in the absence of requirements I'm just making some stuff up */
       if PERSONROLES_TABLETYPE(indx).IS_MANAGER_LEVEL1 = 'Y' then
           personrole_rec.whatever1 := 'something';
       else
           personrole_recc.whatever1 := null;
       end if;
       if PERSONROLES_TABLETYPE(indx).IS_MANAGER_LEVEL2 = 'Y' then
           personrole_rec.whatever2 := 'something else';
       else
           personrole_recc.whatever2 := null;
       end if;
       if personrole_rec.whatever1 is not null 
       or personrole_rec.whatever2 is mot null then
              personroles_recs.exend();
              personroles_recs(personroles_recs.count()) := personroles_rec;
       end if;
  END LOOP;     
  CLOSE REFCUR;
  open p_cursor for 
      select * from table ( personroles_recs );
END GET_PERSONROLES;

此代码使用第二个集合来存储所需的输出。与您的代码一样,它会读取填充的集合并评估每行的属性。如果一个值表示它在行类型变量中设置属性的条件。如果设置了一个或两个属性,则会在第二个集合中填充新行。在过程结束时,它使用第二个集合上的table()函数调用打开引用游标。

请注意,您不需要嵌套循环:您没有使用LIMIT子句,因此您的编码器会将整个光标一次性读入集合中。

实施的规则可能不完全符合您的要求(因为您没有准确解释您想要的内容),但这应该给您一般的想法。

请注意,根据<DO SOME LOGIC AND ASSIGN THE VALUE TO THE ROW>确切掩盖的处理方式,更简单的方法仍然可行:

open P_CURSOR for 
   select case when IS_MANAGER_LEVEL1 = 'Y' then 'YES' else 'NO' end,
          case when IS_MANAGER_LEVEL2 = 'Y' then 'YES' else 'NO' end
   from table ( PERSONROLES_TABLETYPE );