这可能很简单,但我在网上找不到好的例子。我有 5 个游标,我想连续迭代(循环遍历所有游标 1,然后循环遍历所有游标 2,等等)。需要注意的是,我(相信我)需要同时打开所有游标,因为我正在删除循环中的记录,这会影响后面游标中 select 语句的输出...我希望游标反映程序执行开始时的输出,而不是光标循环开始时的输出。
示例:
DECLARE
CURSOR A IS SELECT * FROM tableA;
CURSOR B IS SELECT * FROM tableB;
CURSOR C IS SELECT * FROM tableC;
rowA A%rowtype;
rowB B%rowtype;
rowC C%rowtype;
BEGIN
OPEN A;
OPEN B;
OPEN C;
FOR record IN A LOOP
FETCH A INTO rowA
DELETE FROM ...
END LOOP;
CLOSE A;
FOR record IN B LOOP
FETCH B INTO rowB
DELETE FROM ...
END LOOP;
CLOSE B;
etc
END;
尝试上面的代码片段,我意识到指定“FOR record IN X”会隐式地再次打开游标,这会引发错误。但是,如果我不添加我想要循环的游标,循环如何知道我要循环的游标,因为我打开了 3 个游标?
再次,我需要在循环之前打开所有游标,因为我要删除循环中影响游标的 select 语句返回内容的行。当到达游标C的循环时,如果我当时打开它,游标将不会返回任何行,这不是我想要的。
此示例基于 Scott 的样本
EMP
和 DEPT
表。有两个光标;其中之一显示部门并删除在这些部门工作的员工。另一个显示(或者,正在尝试显示)员工。
样本数据:
SQL> set serveroutput on
SQL> select deptno, dname from dept order by deptno;
DEPTNO DNAME
---------- --------------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
SQL> select deptno, empno, ename from emp order by deptno, ename;
DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7782 CLARK
10 7839 KING
10 7934 MILLER
20 7876 ADAMS
20 7902 FORD
20 7566 JONES
20 7788 SCOTT
20 7369 SMITH
30 7499 ALLEN
30 7698 BLAKE
30 7900 JAMES
30 7654 MARTIN
30 7844 TURNER
30 7521 WARD
14 rows selected.
在第一个示例中,我正在打开 - 然后逐一处理 - 游标(第 9 行和第 20 行):
SQL> declare
2 cursor cur_d is select deptno, dname from dept order by deptno;
3 cur_dr cur_d%rowtype;
4
5 cursor cur_e is select deptno, empno, ename from emp
6 order by deptno, ename;
7 cur_er cur_e%rowtype;
8 begin
9 open cur_d;
10 dbms_output.put_line('Departments ----------');
11 loop
12 fetch cur_d into cur_dr;
13 exit when cur_d%notfound;
14 dbms_output.put_line(cur_dr.deptno ||' - '|| cur_dr.dname);
15 delete from emp where deptno = cur_dr.deptno;
16 dbms_output.put_line('Deleted ' || sql%rowcount ||' employees');
17 end loop;
18 close cur_d;
19
20 open cur_e;
21 dbms_output.put_line('Employees ----------');
22 loop
23 fetch cur_e into cur_er;
24 exit when cur_e%notfound;
25 dbms_output.put_line(cur_er.deptno ||' - '|| cur_er.ename);
26 end loop;
27 close cur_e;
28 end;
29 /
输出显示我删除的部门列表和员工数量。然而,根本没有显示任何员工,因为他们在cur_e
打开之前被删除了:
Departments ----------
10 - ACCOUNTING
Deleted 3 employees
20 - RESEARCH
Deleted 5 employees
30 - SALES
Deleted 6 employees
40 - OPERATIONS
Deleted 0 employees
Employees ----------
PL/SQL procedure successfully completed.
最终结果,emp
表为空:
SQL> select deptno, ename from emp order by deptno, ename;
no rows selected
SQL>
另一个示例在开头打开两个光标(第 9 行和第 10 行):
SQL> rollback;
Rollback complete.
SQL> declare
2 cursor cur_d is select deptno, dname from dept order by deptno;
3 cur_dr cur_d%rowtype;
4
5 cursor cur_e is select deptno, empno, ename from emp
6 order by deptno, ename;
7 cur_er cur_e%rowtype;
8 begin
9 open cur_d;
10 open cur_e;
11 dbms_output.put_line('Departments ----------');
12 loop
13 fetch cur_d into cur_dr;
14 exit when cur_d%notfound;
15 dbms_output.put_line(cur_dr.deptno ||' - '|| cur_dr.dname);
16 delete from emp where deptno = cur_dr.deptno;
17 dbms_output.put_line('Deleted ' || sql%rowcount ||' employees');
18 end loop;
19 close cur_d;
20
21 dbms_output.put_line('Employees ----------');
22 loop
23 fetch cur_e into cur_er;
24 exit when cur_e%notfound;
25 dbms_output.put_line(cur_er.deptno ||' - '|| cur_er.ename);
26 end loop;
27 close cur_e;
28 end;
29 /
部门像以前一样显示,员工被删除,但它们也显示,因为在删除员工之前打开了cur_e
:
Departments ----------
10 - ACCOUNTING
Deleted 3 employees
20 - RESEARCH
Deleted 5 employees
30 - SALES
Deleted 6 employees
40 - OPERATIONS
Deleted 0 employees
全体员工如下:
Employees ----------
10 - CLARK
10 - KING
10 - MILLER
20 - ADAMS
20 - FORD
20 - JONES
20 - SCOTT
20 - SMITH
30 - ALLEN
30 - BLAKE
30 - JAMES
30 - MARTIN
30 - TURNER
30 - WARD
PL/SQL procedure successfully completed.
最终结果是一样的:emp
表为空:
SQL> select deptno, ename from emp order by deptno, ename;
no rows selected
SQL>