如何将行附加到现有的 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?的主要内容,如果未能解决你的问题,请参考以下文章

如何将绘图附加到现有的 pdf 文件

如何将指标附加到现有的 Lambda 日志组?

如何使用附加模式将音频录制到现有的音频文件中?

如何附加到现有的 java.io.ObjectStream? [复制]

如何附加到现有的屏幕会话或创建新的屏幕会话并运行命令?

如何将 Excel 转换为 JSON 并将其附加到现有的 JSON 文件?