Oracle XE 18c PL/SQL 不会在循环内重复打开/获取/关闭第二个游标

发布于 2025-01-15 21:24:12 字数 2652 浏览 3 评论 0原文

信息请求问题

下面的代码按预期工作。完成检查逻辑错误,开头的语法错误,它只是没有帮助(或者我错过了一些?)

问题是外部光标正在工作并且会显示每个记录在其中,但内部光标就像不可见一样,不显示任何内容,也不显示错误消息(显示错误?没有错误)。

但一旦将内显式游标替换为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;
/

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

Information Requesting Question

The code below is working as expected. Done checking logic error, syntax error at the beginning, it just wont help (or I'd missed some?)

The problem is the outer cursor is working and would display every record in it, but the inner cursor is just act like invisible and display nothing nor error message (show errors? No error).

But once the inner explicit cursor replaced by the FOREACH LOOP, the procedure result is perfect.

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;
/

Now it seems like the OPEN statement in a LOOP is not allowed, is it the reason? If not please revive a brain dead man.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

李白 2025-01-22 21:24:12

这是错误的:

OPEN orderDetail_cursor;
IF orderDetail_cursor%FOUND THEN

它从来都不是真的。为什么?因为您必须首先获取才能查看是否找到(或未找到)某些内容。

我没有您的表格,因此我将在 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>

差别很大,不是吗?

This is wrong:

OPEN orderDetail_cursor;
IF orderDetail_cursor%FOUND THEN

It is never true. Why? Because you have to fetch first to see whether something was (or was not) found.

I don't have your tables so I'll demonstrate it on Scott's sample schema. This simulates your code:

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  /

Result is:

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>

But, if you fetch (after opening the cursor) (see line #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  /

Result:

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>

Quite a difference, is it not?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文