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>
差别很大,不是吗?
信息请求问题
下面的代码按预期工作。开始检查逻辑错误,语法错误,它只是无济于事(或者我错过了一些?)
问题是 外部光标 正在工作并且会显示其中的每条记录,但是 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>
差别很大,不是吗?