如何将行附加到现有的 SYS_REFCURSOR?
Posted
技术标签:
【中文标题】如何将行附加到现有的 SYS_REFCURSOR?【英文标题】:How to append rows to a existing SYS_REFCURSOR? 【发布时间】:2020-07-15 07:05:35 【问题描述】:我想知道是否有办法附加到从循环内部获取的游标的结果。
现在 out_cursor 包含与外部 for 循环的最后一次迭代有关的结果。我想知道是否可以将每次迭代中的行附加到此游标中,以便游标包含来自循环的所有迭代的行。
对于上下文,此 out_cursor 由 Java DAO 类使用。
CREATE OR REPLACE NONEDITIONABLE PROCEDURE testproc (out_cursor OUT SYS_REFCURSOR)
IS
CURSOR actor_cursor IS
SELECT actor_id, first_name, last_name
FROM actor
WHERE actor_id <= 100;
row1 actor_cursor%rowtype;
TYPE MyRec IS RECORD (actor_id film_actor.actor_id%TYPE, film_id film_actor.film_id%TYPE);
rec MyRec;
BEGIN
FOR row1 IN actor_cursor
LOOP
dbms_output.put_line('actor_id:'||row1.actor_id ||' ---- '|| row1.first_name || row1.last_name);
OPEN out_cursor FOR
SELECT actor_id, film_id
FROM film_actor
WHERE actor_id = row1.actor_id;
END LOOP;
LOOP -- this loop is here just to print out_cursor for testing
FETCH out_cursor INTO rec;
EXIT WHEN out_cursor%NOTFOUND;
dbms_output.put_line('actor_id:'||rec.actor_id||', film_id:'||rec.film_id);
END LOOP;
END;
脚本的输出是这样的
actor_id:98 ---- CHRIS BRIDGES
actor_id:99 ---- JIM MOSTEL
actor_id:100 ---- SPENCER DEPP
actor_id:100, film_id:17
actor_id:100, film_id:118
我知道只有来自 for 循环最后一次迭代的行在 out_cursor 中。
有什么办法可以让out_cursor返回外层FOR LOOP所有迭代的结果,本质上是聚合所有迭代的结果。产生这样的结果?
actor_id:98 ---- CHRIS BRIDGES
actor_id:99 ---- JIM MOSTEL
actor_id:100 ---- SPENCER DEPP
actor_id:98, film_id:77 // results from iteration #1
actor_id:98, film_id:43
actor_id:99, film_id:67 // results from iteration #2
actor_id:99, film_id:90
actor_id:100, film_id:17 // results from iteration #3
actor_id:100, film_id:118
我知道我可以使用 JOINS 轻松归档相同的结果。但是我不能修改 SQL 查询(实际的 SQL 非常复杂)——我只能运行它们并将一个 SQL 产生的结果用作下一个 SQL 的参数(在 SELECT 或 WHERE 子句中)。
(更新) 一般要求是 - 有一系列查询,每个查询的结果集用于下一个的约束。我不能自己修改查询 - 所以使用连接或子查询是不可能的。
我希望为每个查询打开一个游标,然后遍历游标中的值 - 使用下一个查询的约束中的游标属性,为此我将在 for 循环中打开一个游标。完全如示例中所示。但问题是循环内的光标只包含上次迭代中所做的选择——在每次迭代期间,都会创建一个新的光标。所以,我在 out_cursor 中只得到了我想要的结果的一个子集。
我想我找到了一种方法来做到这一点 -
CREATE OR REPLACE PACKAGE PKG_BIDS_REPORTS_TEST as
TYPE Q2DATA IS RECORD (
actor_id film_actor.actor_id%TYPE,
film_id film_actor.film_id%TYPE
);
TYPE Q2DATA_TAB IS TABLE OF Q2DATA INDEX BY BINARY_INTEGER;
Q2DATA_REC Q2DATA_TAB;
PROCEDURE pqr_reports_test(l_out_data OUT sys_refcursor);
end PKG_BIDS_REPORTS_TEST;
/
create or replace NONEDITIONABLE PACKAGE BODY PKG_BIDS_REPORTS_TEST as
PROCEDURE pqr_reports_test(l_out_data OUT sys_refcursor) AS
CURSOR actor_cursor IS
SELECT actor_id, first_name, last_name
FROM actor
WHERE actor_id <= 100;
row1 actor_cursor%rowtype;
CURSOR film_actor_cursor(actorid film_actor.actor_id%TYPE) IS
SELECT actor_id, film_id
FROM film_actor
WHERE actor_id = actorid;
row2 film_actor_cursor%rowtype;
V_CNT NUMBER:=0;
BEGIN
V_CNT := q2data_rec.COUNT;
FOR row1 IN actor_cursor
LOOP
--dbms_output.put_line(row1.actor_id ||' ---- '|| row1.first_name ||' ---- '|| row1.last_name);
FOR row2 IN film_actor_cursor(row1.actor_id)
LOOP
V_CNT := V_CNT + 1;
q2data_rec(V_CNT).actor_id := row2.actor_id;
q2data_rec(V_CNT).film_id := row2.film_id;
--dbms_output.put_line(row2.actor_id||','||row2.film_id);
END LOOP;
END LOOP;
OPEN L_OUT_DATA FOR SELECT DISTINCT datarec.actor_id, datarec.film_id from TABLE(q2data_rec) datarec;
END;
End PKG_BIDS_REPORTS_TEST;
本质上是创建一个 PLSQL 表并在循环中填充一个像 Java 数组这样的计数器。有用。绝对不是最优雅的。
因此,我绝对会感谢任何优化或替代方案。
【问题讨论】:
没有办法扩展游标的内容。游标包含 SINGLE 选择语句的结果。见here。请提供您正在尝试的完整示例,可能类似于minimal reproducible example 和完整示例数据(另请参阅How to Ask)。然后社区才能提供满意的答案。 【参考方案1】:为了获得您期望的输出,您不能在打开第二个光标之前关闭第一个光标。这是合并两个迭代的唯一方法。
虽然效率不高,但有一种方法
BEGIN
FOR row1 IN actor_cursor
LOOP
dbms_output.put_line(row1.actor_id ||' ---- '|| row1.first_name || row1.last_name);
OPEN out_cursor FOR
SELECT actor_id, film_id
FROM film_actor
WHERE actor_id = row1.actor_id;
END LOOP;
FOR row1 IN actor_cursor
LOOP
OPEN out_cursor FOR
SELECT actor_id, film_id
FROM film_actor
WHERE actor_id = row1.actor_id;
LOOP
FETCH out_cursor INTO rec;
EXIT WHEN out_cursor%NOTFOUND;
dbms_output.put_line(row1.actor_id ||','|| rec.film_id);
END LOOP;
END LOOP;
END;
【讨论】:
抱歉,我可能不清楚 - 将 print 语句移到循环中并不能解决我的问题。目标是让 out_cursor(由 java DAO 类使用)拥有所有迭代的内容,而不仅仅是最后一个。最后一个循环仅用于打印该游标的结果以进行测试。 没问题,我没有从问题中得到。您需要从 java DAO 类中的过程获得什么输出?你能在问题本身中澄清这一点吗?【参考方案2】:正如我之前指出的,您不能组合单独游标的结果。但是,您可以(至少在这种情况下)将它们组合成一个选择并返回该结果。而且由于您正在返回一个参考光标,除非您关闭并重新打开它,否则您无法循环访问它。所以在这种情况下,您的过程应该由一个打开的游标语句组成。
create or replace
procedure testproc (out_cursor out sys_refcursor)
is
begin
open out_cursor for
select a.actor_id, a.first_name, a.last_name, fa.film_id
from actor a
join film_actor fa
on fa.actor_id = a.actor_id
where a.actor_id <= 100;
end testproc ;
------- test ------
declare
actor_id actor.actor_id%type
fname actor.first_name%type
l_name actor,last_name%type
film_id film.film_id%type;
rec sys_refcursor ;
begin
testproc(rec);
loop
fetch rec
into actor_id, fname, lname, film_id;
exit when rec%notfound;
dbms_output.put_line('actor_id:' || actor_id ||
' name: ' || fname || ' ' || lname
' film_id:' || film_id
);
end loop;
end ;
【讨论】:
我知道 SQL 连接是一种可能性,但对我来说它不起作用,因为我不“拥有” SQL 查询。无论如何,谢谢。以上是关于如何将行附加到现有的 SYS_REFCURSOR?的主要内容,如果未能解决你的问题,请参考以下文章