Oracle XE 18c PL/SQL 不要重复 open/fetch/close 循环内的第二个游标

Oracle XE 18c PL/SQL do not repeatedly open/fetch/close the second cursor inside a loop

信息请求问题

下面的代码按预期工作。开始检查逻辑错误,语法错误,它只是无济于事(或者我错过了一些?)

问题是 外部光标 正在工作并且会显示其中的每条记录,但是 inner cursor就像看不见的一样,什么也不显示,也不显示错误信息(显示错误?没有错误)。

但是一旦内部显式游标FOREACH LOOP,程序效果完美

CREATE OR REPLACE PROCEDURE prc_order_details AS
--variable declaration
v_orderNo ORDERS.orderNumber%TYPE;
v_orderDate ORDERS.orderDate%TYPE;
v_requiredDate ORDERS.requiredDate%TYPE;
v_shippedDate ORDERS.shippedDate%TYPE;
v_custNo ORDERS.customerNumber%TYPE;

v_productCode ORDERDETAILS.productCode%TYPE;
v_qtyOrd ORDERDETAILS.quantityOrdered%TYPE;
v_priceEach ORDERDETAILS.priceEach%TYPE;

--cursor declaration
cursor order_cursor is
select customerNumber, orderNumber, orderDate, requiredDate, shippedDate
from ORDERS;

cursor orderDetail_cursor is
select productCode, quantityOrdered, priceEach
from ORDERDETAILS
where orderNumber = v_orderNo;

--processing
BEGIN

    OPEN order_cursor;
    LOOP
        FETCH order_cursor
        INTO v_custNo, v_orderNo, v_orderDate, v_requiredDate, v_shippedDate;
        DBMS_OUTPUT.PUT_LINE('Customer No : '||v_custNo);
        DBMS_OUTPUT.PUT_LINE('Order No : '||v_orderNo);
        DBMS_OUTPUT.PUT_LINE('Order Date : '||v_orderDate);
        DBMS_OUTPUT.PUT_LINE('Shipped : '||v_shippedDate);
        DBMS_OUTPUT.PUT_LINE('Required Date : '||v_requiredDate);
        dbms_output.put_line(chr(10));
    
        /*---   these code did not work as expected   ----
        OPEN orderDetail_cursor;
            IF orderDetail_cursor%FOUND THEN
                DBMS_OUTPUT.PUT_LINE('got something to fetch');
            ELSIF orderDetail_cursor%NOTFOUND THEN
                DBMS_OUTPUT.PUT_LINE('got nothing to fetch');
            END IF;

            WHILE orderDetail_cursor%FOUND
            LOOP
                FETCH orderDetail_cursor
                INTO v_productCode, v_qtyOrd, v_priceEach;
                DBMS_OUTPUT.PUT_LINE(v_productCode||'***'||v_qtyOrd||'***'||v_priceEach);
            END LOOP;
        CLOSE orderDetail_cursor;
        */
        
        FOR detail IN orderDetail_cursor
        LOOP
           dbms_output.put_line(detail.productCode||'***'||detail.quantityOrdered||'***'||detail.priceEach);
        END LOOP;
        
        
        DBMS_OUTPUT.PUT_LINE('End of Customer '||v_custNo||'************************');
        dbms_output.put_line(chr(10));
    
    
        EXIT WHEN order_cursor%NOTFOUND;
    END LOOP;
    CLOSE order_cursor;
END;
/

现在看来 OPEN 语句在 LOOP不允许,是这个原因吗?如果不是请复活一个脑死亡的人。

这是错误的:

OPEN orderDetail_cursor;
IF orderDetail_cursor%FOUND THEN

它永远不会 正确 。为什么?因为您必须先 fetch 以查看是否找到(或未找到)某些内容。

我没有您的表格,所以我将在 Scott 的示例架构中进行演示。这模拟了您的代码:

SQL> declare
  2    v_deptno number;
  3    v_ename  varchar2(10);
  4    v_job    varchar2(20);
  5    cursor cout is select deptno from dept order by deptno;
  6    cursor cin is
  7      select ename, job from emp
  8      where deptno = v_deptno;
  9  begin
 10    open cout;
 11    loop
 12      fetch cout into v_deptno;
 13      dbms_output.put_line('Deptno = ' || v_deptno);
 14
 15      open cin;
 16      if cin%found then
 17         dbms_output.put_line('got something');
 18      else
 19         dbms_output.put_line('got nothing');
 20      end if;
 21
 22      while cin%found loop
 23        fetch cin into v_ename, v_job;
 24        dbms_output.put_line(v_ename ||': '|| v_job);
 25      end loop;
 26
 27      close cin;
 28      exit when cout%notfound;
 29    end loop;
 30    close cout;
 31  end;
 32  /

结果是:

Deptno = 10
got nothing
Deptno = 20
got nothing
Deptno = 30
got nothing
Deptno = 40
got nothing
Deptno = 40
got nothing

PL/SQL procedure successfully completed.

SQL>

但是,如果您获取(在打开游标之后)(参见第 16 行):

SQL> declare
  2    v_deptno number;
  3    v_ename  varchar2(10);
  4    v_job    varchar2(20);
  5    cursor cout is select deptno from dept order by deptno;
  6    cursor cin is
  7      select ename, job from emp
  8      where deptno = v_deptno;
  9  begin
 10    open cout;
 11    loop
 12      fetch cout into v_deptno;
 13      dbms_output.put_line('Deptno = ' || v_deptno);
 14
 15      open cin;
 16      fetch cin into v_ename, v_job;                --> here
 17      if cin%found then
 18         dbms_output.put_line('got something');
 19      else
 20         dbms_output.put_line('got nothing');
 21      end if;
 22
 23      while cin%found loop
 24        fetch cin into v_ename, v_job;
 25        dbms_output.put_line(v_ename ||': '|| v_job);
 26      end loop;
 27
 28      close cin;
 29      exit when cout%notfound;
 30    end loop;
 31    close cout;
 32  end;
 33  /

结果:

Deptno = 10
got something
KING: PRESIDENT
MILLER: CLERK
MILLER: CLERK
Deptno = 20
got something
JONES: MANAGER
SCOTT: ANALYST
ADAMS: CLERK
FORD: ANALYST
FORD: ANALYST
Deptno = 30
got something
WARD: SALESMAN
MARTIN: SALESMAN
BLAKE: MANAGER
TURNER: SALESMAN
JAMES: CLERK
JAMES: CLERK
Deptno = 40
got nothing
Deptno = 40
got nothing

PL/SQL procedure successfully completed.

SQL>

差别很大,不是吗?