Oracle:如何将 populate/insert 行添加到 Ref Cursor?

Oracle: How to populate/insert row to a Ref Cursor?

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

程序依赖于这个公开声明的类型:

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

这是我的伪代码L

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;

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

不变性是有道理的,因为它反映了 Oracle 对读取一致性的重视。

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

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

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


"Ok edited it now"

唉,你的要求还是不明确。您没有给我们输出引用游标的结构,也没有显示您要进行的其他处理。

但是,鉴于您的问题标题,让我们猜猜。所以:

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;

此代码使用第二个 collection 来存储所需的输出。就像您的代码一样,它读取填充的 collection 并评估每一行的属性。如果一个值表示标准,它会在 rowtype 变量中设置一个属性。如果设置了一个或两个属性,它会在一秒钟内填充一个新行 collection。在过程结束时,它使用 table() 函数调用在第二个 collection.

上打开引用游标

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

实施的规则可能不是您想要的(因为您没有准确解释您想要的),但这应该给您一个大概的想法。

请注意,根据 <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 );