你正在消耗
v_RC_union
在外循环的第一次迭代期间。您似乎期望每次循环时都能看到所有这些行,但是第二个ref光标并没有重置为开始位置(而且不能重置)。
如果将调试添加到代码中,您可以看到正在发生这种情况;我已经创建了两个小的虚拟表,每个表中有三个匹配的ID和一个不匹配的ID:
create table table1 (id, dummy) as select level + 1, 'x' from dual connect by level <= 4;
create table table2 (id, dummy) as select level, 'x' from dual connect by level <= 4;
declare
...
begin
open v_RC for select * from table1;
open v_RC_union for select * from table2;
loop
fetch v_RC into v_REC;
exit when v_RC%notfound;
i := i+1;
dbms_output.put_line('i: ' || i || ' table1 id ' || v_REC.id);
loop
fetch v_RC_union into v_REC_union;--
exit when v_RC_union%notfound;
j := j+1;
dbms_output.put_line('i: ' || i || ' j: ' || j || ' table1 id ' || v_REC_union.id);
If v_REC_union.id= v_REC.id then
z :=z+1;
end if;
end loop;
end loop;
close v_RC;
close v_RC_union;
dbms_output.put_line('z: ' || z);--too small
dbms_output.put_line('v_RC: '||i||', v_REC_union: '||j);
end;
/
其输出为:
i: 1 table1 id 2
i: 1 j: 1 table1 id 1
i: 1 j: 2 table1 id 2
i: 1 j: 3 table1 id 3
i: 1 j: 4 table1 id 4
i: 2 table1 id 3
i: 3 table1 id 4
i: 4 table1 id 5
z: 1
v_RC: 4, v_REC_union: 4
在第一次迭代中,当
i
是1,执行内部循环并从
工会
,仅当
notfound
. 假设其中一个和第一个匹配
v_RC
行的ID
z
是递增的,所以在第一个外部循环之后是1或0。
在第二次迭代中,当
我
为2,内环在第一次取出后立即退出,因为您已经用完了。
工会
结果集。您在第一次迭代中获取了它的所有行,因此没有任何内容可供获取。所以,不是那一秒
钢筋混凝土
row的ID从未与任何内容进行过比较,并且
z轴
别碰它,因为它不会走那么远。
对于外部循环的所有其他迭代,依此类推。内循环总是立即退出,不做任何有用的事情。
你可以再问
table2
对于每次在答案中显示的特定ID,尽管如果只计算它们而不使用任何列值,那么实际上不需要open/loop/fetch,只需将该查询更改为一个count到一个标量变量。不过,即使是逐行处理,这似乎也不是很有效。
如果要坚持使用整个表查询,可以使用集合:
declare
type t_table1 is table of table1%rowtype;
type t_table2 is table of table2%rowtype;
v_table1 t_table1;
v_table2 t_table2;
i number := 0;
j number := 0;
z number := 0;
begin
select * bulk collect into v_table1 from table1;
select * bulk collect into v_table2 from table2;
for r1 in v_table1.first..v_table1.last loop
i := i+1;
dbms_output.put_line('i: ' || i || ' table1 id ' || v_table1(r1).id);
j := 0;
for r2 in v_table2.first..v_table2.last loop
j := j+1;
dbms_output.put_line('i: ' || i || ' j: ' || j || ' table2 id ' || v_table2(r2).id);
if v_table2(r2).id = v_table1(r1).id then
z := z+1;
end if;
end loop;
end loop;
dbms_output.put_line('z: ' || z);
dbms_output.put_line('v_RC: '||i||', v_REC_union: '||j);
end;
/
通过循环遍历两个集合
我
迭代看到
j
行并可以比较ID。
i: 1 table1 id 2
i: 1 j: 1 table2 id 1
i: 1 j: 2 table2 id 2
i: 1 j: 3 table2 id 3
i: 1 j: 4 table2 id 4
i: 2 table1 id 3
i: 2 j: 1 table2 id 1
i: 2 j: 2 table2 id 2
i: 2 j: 3 table2 id 3
i: 2 j: 4 table2 id 4
i: 3 table1 id 4
i: 3 j: 1 table2 id 1
i: 3 j: 2 table2 id 2
i: 3 j: 3 table2 id 3
i: 3 j: 4 table2 id 4
i: 4 table1 id 5
i: 4 j: 1 table2 id 1
i: 4 j: 2 table2 id 2
i: 4 j: 3 table2 id 3
i: 4 j: 4 table2 id 4
z: 3
v_RC: 4, v_REC_union: 4
当您可以使用set运算符直接在普通SQL中进行计数和比较时,这似乎仍然需要做很多工作,例如:
select
(select count(*) from table1) as i,
(select count(*) from table2) as j,
(select count(*) from (select id from table1 intersect select id from table2)) as z
from dual;
I J Z
---------- ---------- ----------
4 4 3
在这里使用PL/SQL似乎并没有太大的好处;SQL版本可能会做更多的工作,因为它查询两个表两次(虽然可能会碰到缓存),但是无论如何,您可以使用cte来避免这一点,而且总体上可能比使用PL/SQL快。