在Oracle中循环遍历游标时使用EXIT WHEN指令是一种不好的做法吗?
这听起来可能是一个愚蠢的问题,但我希望我能说清楚在Oracle中循环遍历游标时使用EXIT WHEN指令是一种不好的做法吗?,oracle,coding-style,cursor,conditional,Oracle,Coding Style,Cursor,Conditional,这听起来可能是一个愚蠢的问题,但我希望我能说清楚 当谈到它时,它的基础是 GOTOs的使用。我有一位同行曾经说过,如果我在代码末尾放了一个断点,但每次都没有到达这个断点,那么一定是出了问题 然而,这是一个常见的(我想说,是一个规则)使用 Oracle包中的结构(通常后跟%NOTFOUND 测试) 理所当然地认为使用EXIT会中断编程流程,这不是1和2之间不匹配的事情吗 每个人都在用PL/SQL编程吗?PL/SQL是否不遵循这个特定的条件模式 在甲骨文的庇护下,是否有任何性能理由使用此类语句 抱歉
%NOTFOUND
测试)EXIT
会中断编程流程,这不是1和2之间不匹配的事情吗
每个人都在用PL/SQL编程吗?PL/SQL是否不遵循这个特定的条件模式
在甲骨文的庇护下,是否有任何性能理由使用此类语句
抱歉,如果已经问过这个问题,我找不到任何类似的问题。非常建议在您的代码中保持简单,这样我就可以告诉您PL/SQL专家对它的看法: 注意:在某些情况下,不建议使用游标循环。你可以考虑一种更智能的方式,根据你的需要选择单选或批量收集。 (参考:): 循环 12。利用光标进行循环。 循环的光标为 我最喜欢的PL/SQL结构之一。它充分利用了紧密的 有效地将语言的程序方面与 SQL数据库语言的强大功能。它减少了代码量 您需要写入以从游标获取数据。这大大降低了成本 在您的编程中引入循环错误的机会-并且循环是 程序中最容易出错的部分之一。这个环路响吗 好得难以置信?好吧,不是的,都是真的 假设我需要更新所有宠物的账单 共享丁丁酒店。下面的示例包含一个 使用光标Occupation\u cur选择房间的匿名块 酒店所有入住者的号码和宠物ID号。程序 更新账单增加了宠物房间费用的任何新变化
DECLARE
CURSOR occupancy_cur IS
SELECT pet_id, room_number
FROM occupancy
WHERE occupied_dt = SYSDATE;
occupancy_rec occupancy_cur%ROWTYPE;
BEGIN
OPEN occupancy_cur;
LOOP
FETCH occupancy_cur
INTO occupancy_rec;
EXIT WHEN occupancy_cur%NOTFOUND;
update_bill
(occupancy_rec.pet_id,
occupancy_rec.room_number);
END LOOP;
CLOSE occupancy_cur;
END;
这段代码让人无法想象。除了定义
在游标(第2行)中,必须显式声明
光标(第5行),打开光标(第7行),启动无限循环,
从光标集中提取一行到记录中(第9行),检查
使用游标属性结束数据条件(第10行),最后
执行更新。当你做完了,你必须记住
关闭光标(第14行)。如果我将此PL/SQL块转换为使用
光标用于循环,则我所拥有的是:
DECLARE
CURSOR occupancy_cur IS
SELECT pet_id, room_number
FROM occupancy WHERE occupied_dt =
SYSDATE;
BEGIN
FOR occupancy_rec IN occupancy_cur
LOOP
update_bill (occupancy_rec.pet_id,
occupancy_rec.room_number);
END LOOP;
END;
在这里,您可以看到游标FOR循环的简单性!过去了
记录的声明。打开、取出和关闭的门都不见了
声明。需要检查%FOUND属性。这些东西都不见了
担心一切都会好起来。相反,您可以对PL/SQL说
效果:Ò你和我都知道我想要每一行,我想要转储
将该行转换为与光标匹配的记录。为你照顾好那件事
我,你会吗?“PL/SQL确实会处理它,就像任何一种方式一样
与SQL集成的现代编程语言应该是
是的,很多人都在遵循一个坏习惯 糟糕的风格 我同意@Osy的观点,即OPEN/FETCH/CLOSE添加了完全不必要的代码。我甚至要说,您几乎不应该使用
游标
首先,您通常希望尽可能多地使用纯SQL。如果您需要使用PL/SQL,请使用隐式游标。它将为您节省一行代码,并帮助您将相关逻辑保持在一起
我非常相信保持单个代码单元尽可能小。乍一看,光标可以帮助您做到这一点。您可以在一个位置上定义SQL,然后稍后再执行PL/SQL循环
但在现实中,这种额外的间接层几乎是不值得的。有时很多逻辑在SQL中,有时很多逻辑在PL/SQL中。但在实践中,在两者中都放很多复杂的逻辑是没有意义的。您的代码通常看起来像
其中一项:
for records in (<simple SQL>) loop
<complex PL/SQL>
end loop;
用于()循环中的记录
端环;
或:
中的记录
(
)环路
;
端环;
无论哪种方式,您的一个代码段都会非常小。分离这两个代码段的复杂性要比单个更大代码段的复杂性大。(但这显然是我的观点。)
性能差
使用OPEN/FETCH/CLOSE会对性能产生重大影响。该方法比使用游标for循环或隐式游标慢得多
编译器可以在某些for循环中自动使用大容量收集。但是,引用Oracle演示文稿第122页:
不要使用打开、获取循环、关闭表单来浪费这个机会
下面是一个简单的例子:
--Sample data
create table t(a number, b number);
insert into t select level, level from dual connect by level <= 100000;
commit;
--OPEN/FETCH/CLOSE
--1.5 seconds
declare
cursor test_cur is
select a, b from t;
test_rec test_cur%rowtype;
counter number;
begin
open test_cur;
loop
fetch test_cur into test_rec;
exit when test_cur%notfound;
counter := counter + 1;
end loop;
close test_cur;
end;
/
--Implicit cursor
--0.2 seconds
declare
counter number;
begin
for test_rec in (select a, b from t) loop
counter := counter + 1;
end loop;
end;
/
——示例数据
创建表t(a号、b号);
插入到t select level,level from dual connect by level Hi Osi,这是一篇很棒的文章,谢谢!我喜欢在不使用EXIT WHEN
条件时处理FOR
循环的方法。你知道这种结构是否可以在任何地方使用吗?我的意思是,是否可以用这种对于
loop?Right Tiago,即使游标有参数或您使用的是动态sql,您也可以替换所有退出选项。这两个答案都很好,只需将这一个明确标记为“更好”答案,因为它清楚地说明了两件事:这是一种不好的做法,并且还比较了这两种方法。
--Sample data
create table t(a number, b number);
insert into t select level, level from dual connect by level <= 100000;
commit;
--OPEN/FETCH/CLOSE
--1.5 seconds
declare
cursor test_cur is
select a, b from t;
test_rec test_cur%rowtype;
counter number;
begin
open test_cur;
loop
fetch test_cur into test_rec;
exit when test_cur%notfound;
counter := counter + 1;
end loop;
close test_cur;
end;
/
--Implicit cursor
--0.2 seconds
declare
counter number;
begin
for test_rec in (select a, b from t) loop
counter := counter + 1;
end loop;
end;
/