基本上,游标是内存区域,用于存储特定查询的结果。我有一个问题是游标是否隐式循环遍历所有记录?假设我编写了如下代码片段:
declare
cursor cur_dum is
select name,class,enroll_id from table_student;
begin
fetch cur_dum into the_name, the_class, the_enroll_id;
update table_log set statement = the_name || '-'||'-'||to_char(the_enroll_id)
where roll_id = the_enroll_id;
close cur_dum;
end;
这个代码片段,没有任何明确的循环语句,会自动遍历table_student中的所有记录并在table_log中执行相应的更新吗?我需要在fetch语句之后添加一个循环吗?如果我在提取过程中使用批量收集语句会有什么不同?
从答案中,我得到明确说明循环是必要的。
我遇到了一段代码片段,它使用了一个游标循环,并在其中使用了一个for循环。以下是代码片段:
Cursor CurSquirell IS
select Name,a_val,b_val,col_ID from table_temp;
BEGIN
LoopCounter := 0;
commit;
LOOP
FETCH CurSquirell BULK COLLECT INTO my_name,my_a_val,my_b_val,my_col_id LIMIT 1000;
LoopCounter := LoopCounter + 1;
FOR intIndex IN 1 .. my_col_id.COUNT LOOP
counter := counter +1;
BEGIN
select t.tender_val,t.tender_pay, t.page_no, t.loc
into my_tender_val,my_tender_pay,my_page_no , my_loc
from bussiness_trans bt, tender_details t
where t.account_no = bt.account_no
and bt.external_id=my_col_id(intIndex)
and trim(replace(t.tender_pay,'0',' ')) = trim(replace(a_val(intIndex),'0',' '))
and bt.id_type=1;
BEGIN
select pp.lock_id into my__lock_id
from pay_roll pp
where pp.pay_points= my_tender_pay
and bt.id_type=5;
BEGIN
update tab_cross_exchange tce
set tce.cross_b_val = my_b_val(intIndex)
where tce.lock_id = my_lock_id;
..............................sql statements...
...sql statements...
end;
end;
end;
当代码循环已经被用于逐个浏览记录时,为什么使用了for loop
?在什么情况下你需要在游标循环中使用这样的for loop
?批量收集是否必须采取任何措施来强制使用For循环?
答案 0 :(得分:1)
“游标是用于存储特定查询结果的内存区域”
不完全。游标是指向用于存储有关查询的信息的内存区域的指针。查询结果存储在内存的其他区域。
您使用的PL / SQL语法指定了一个定义查询的变量。要执行查询,您需要
每次提取都会返回一行。要耗尽查询,您需要在循环中执行提取。这是这样做的冗长方式:
declare
cursor cur_dum is
select name,class,enroll_id from table_student;
rec_dum cur_dum%rowtype;
begin
open cur_dum;
loop
fetch cur_dum into rec_dum;
exit when cur_dum%notfound;
update table_log
set statement = rec_dum.name || '-'||'-'||to_char(rec_dum.enroll_id)
where roll_id = rec_dum.enroll_id;
end loop;
close cur_dum;
end;
注意:这种显式游标符号的一个好处是我们可以定义一个类型为光标查询投影的变量(上面是rec_dum
)。
这与使用隐式光标表示法的逻辑相同:
declare
cursor cur_dum is
rec_dum cur_dum%rowtype;
begin
for rec_dum in (select name,class,enroll_id from table_student)
loop
update table_log
set statement = rec_dum.name || '-'||'-'||to_char(rec_dum.enroll_id)
where roll_id = rec_dum.enroll_id;
end loop;
end;
“批量收集是否必须做任何事情来强制使用For循环?”
BULK COLLECT是允许我们使用一组记录填充嵌套表变量的语法,因此执行批量处理而不是上面说明的基本FETCH的逐行处理;您引用的代码段一次抓取一个包含1000条记录的子集,这在处理大量数据时是必需的,因为变量会填充私有(会话)内存而不是全局(共享内存)。您引用的代码非常差,尤其是因为FETCH ... BULK COLLECT INTO语句后面没有测试FETCH是否返回任何值。因为没有测试,后续代码将在运行时失败。
“在游标循环中使用for循环会使代码变差吗?”
不,不是自动的。例如,在进行批量处理时,我们可能经常做这样的事情:
<< batch_loop >>
loop
fetch dum_cur bulk collect into dum_recs limit 1000;
exit when dum_recs.count() = 0;
<< row_loop >>
for idx in dum_recs.first()..dum_recs.last()
loop
do_something(dum_recs(idx));
end loop row_loop;
end loop batch_loop;
但是,我们应该怀疑嵌套的CURSOR FOR循环。嵌套循环在像Java这样的3GL程序中很常见:
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 10; j++) {
因此,熟悉这种编码风格的开发人员在迁移到PL / SQL时经常会遇到嵌套循环。但SQL是一种基于集合的范例。通常有更好的方法来实现该逻辑,例如JOIN:将两个游标合二为一。