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()
调用,您可能需要将 REFTABLETYPE
和 TABLETYPE
声明为 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 );
确实需要有关 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()
调用,您可能需要将 REFTABLETYPE
和 TABLETYPE
声明为 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 );