PL/SQL程序结构
本文将介绍PL/SQL的程序结构,将会涉及到分支和顺序结构,循环结构,异常处理等。
我写这篇文章的目的是为了在我阅读《Oracle.PL.SQL程序设计》一书是做些笔记,并分享给其他同学。
PL/SQL的分支和顺序结构
IF 结构
PL/SQL的IF结构主要是if…then…end if 结构,衍生出 if-else 还有 if-elsif-else等结构。
IF - THEN 结构
create or replace procedure demo1(num1 in number,num2 out number)
is
begin
IF num1<5
THEN num2 := num1;
END IF;
end;
在IF-THEN结构中 IF 后是一个布尔类型的变量,常量或者表达式,当结果为TRUE时执行THEN后面的语句,当结果为FALSE 或者 NULL时,结束IF语句。
在这里要说一下布尔表达式的三值逻辑,通常我们理解的布尔表达式的结果只有TRUE 以及 FALSE。 在PL/SQL中,如果一个表达式包含NULL值时,布尔表达式的结果为NULL。如果我们想避免NULL值的出现,可以采取以下方式,虽然我认为没有什么意义。
IF num1<5 OR num1 is not null
THEN num2 := num1;
END IF;
IF - THEN -ELSE结构
这类结构通常是用于两个互斥选择,类似“或者…或者…”。
create or replace procedure demo2(num1 in number,num2 out number)
is
begin
IF num1<5 or num1 >10
THEN num2 := num1;
ELSE
num2 := null;
END IF;
end;
IF - THEN -ELSIF 结构
如果你的选择有很多分支,这个结构是一个不错的选择。
create or replace procedure demo3(num1 in number,num2 out number)
is
begin
IF num1<5 or num1 >10
THEN num2 := num1;
ELSIF num1 is null
Then num2 := 0;
ELSE
num2 := 6;
END IF;
end;
IF 的嵌套
create or replace procedure demo4(num1 in number,num2 out number)
is
begin
IF num1<5 or num1 >10
THEN
IF num1 >0
then num2 := num1;
ELSE
num2 := (0-num1);
END IF;
ELSIF num1 is null
Then num2 := 0;
ELSE
num2 := 6;
END IF;
end;
IF 语法值得注意的地方
- 每个IF都要匹配一个END IF; 这个就像是HTML中的标签,既然有< 就要有 />。
- ELSIF 没有E,这个地方常常被我忽视。
- 每个ELSIF 都要有THEN ,只有ELSE不需要THEN,
- 短路求值,这个特性和其他语言一样,如果A AND B , 当A为false时,B不必执行,因为整个表达式的结果已经被确定。
PL/SQL的CASE结构
case结构用于在多个可能的情况下选择一种处理方式。PL/SQL从Oracle 9i 才支持case结构的。
简单CASE结构
create or replace procedure demo5(num1 in number,num2 out number)
is
begin
case num1
when 1 then num2 :=(0-num1);
when 2 then num2 :=(0-num1);
when 3 then num2 :=(0-num1);
when 4 then num2 :=(0-num1);
else num2 := 0;
end case;
end;
可能大家了解过java,在java中的switch结构和这里的case有些类似,不同的地方时switch是由case选择入口顺序执行下去,直至遇到break等跳出switch,而我们PL/SQL中的case是根据表达式选择一种情况执行。
选择型CASE结构
一个选择型的case对应一系列的布尔表达式,当某一个表达式结果为TRUE时,则处理对应的逻辑。
create or replace procedure demo6(num1 in number,num2 out number)
is
begin
case
when num1>1 then num2 :=1;
when num1>2 then num2 :=2;
when num1>3 then num2 :=3;
when num1>4 then num2 :=4;
else num2 := 0;
end case;
end;
case表达式
case表达式只返回一个单独的值。
create or replace procedure demo7(num1 in number,num2 out number)
is
begin
num2 := case
when num1=1 then 1
when num1=2 then 2
when num1=3 then 3
when num1=4 then 4
else 0
end;
end;
case结构值得注意的是:
- else 是可选的,但是没有else 而且 没有对应的情况发生时,会报错为 : CASE_NOT_FOUNT(case表达式除外,它会返回null)。
- case表达式中的结果是一个值,并且不需要以分号结尾。
- case表达式的结尾为 end,而不是 end case。
NULL语句
一般而言,我们写语句,都希望让它干点什么,无论是什么,但是null语句是个相反,可能它比较懒吧。它的最好搭档就是GOTO语句了。因为GOTO语句可以让你少执行一部分语句。但是GOTO语句后面必须有可执行语句,但是当我们又没有什么可执行的使用,就可以写NULL啦。
create or replace procedure demo8
is
begin
dbms_output.put_line('test the goto');
goto the_point;
dbms_output.put_line('这条语句不会输出');
<<the_point>>
null;
end;
PL/SQL的循环结构
简单循环 LOOP
create or replace procedure demo9(s_num in number,e_num in number,onum out number)
is
subnum number;
start_num number;
begin
subnum :=0;
start_num := s_num;
LOOP
/*if start_num = e_num
then exit;
end if;
*/
EXIT WHEN start_num = e_num;
subnum := subnum + start_num;
start_num:=start_num+1;
end loop;
onum := subnum;
end;
在LOOP循环中 以LOOP开头,以end loop 结尾,退出循环只能依靠EXIT 或者 EXIT WHEN… 。
while 循环
while循环是一个条件循环,当满足条件是循环,脂质无法满足条件。
create or replace procedure demo10(s_num in number,e_num in number,onum out number)
is
subnum number;
start_num number;
begin
subnum :=0;
start_num := s_num;
WHILE start_num<e_num
LOOP
subnum := subnum + start_num;
start_num := 1+ start_num;
END LOOP;
ONUM := subnum;
end;
我们也可以使用LOOP循环搭配EXIT WHEN实现类似循环过程。
数值型for循环
for循环是一种计数循环,它的迭代次数在循环一开始就界定好了,在循环中不允许更改循环计数的起始边界和终止边界。REVERSE关键字可以实现从终止边界递减计数至其实边界。
create or replace procedure demo12(
onum out number)
is
subnum number;
begin
subnum := 0;
FOR var IN reverse 1..5
LOOP
subnum := var + subnum;
END LOOP;
ONUM := subnum;
end;
值得注意的是,使用REVERSE时不必颠倒起始边界和终止边界,也必须把大值放到小值前面。数值型for循环无法改变步长(如何增长),步长只能为1,所以我们只能通过改变索引的方式进行我们的操作。
游标型for循环
游标型for循环是和一个显示的游标或者一个在边界中写入的SELECT语句。
当我们没有for循环时,通常是这样子:
create or replace procedure demo14
is
CURSOR M_CURSOR IS
select * from emp;
EMP_INFO M_CURSOR%ROWTYPE;
begin
OPEN M_CURSOR;
LOOP
FETCH M_CURSOR INTO EMP_INFO;
EXIT WHEN M_CURSOR%NOTFOUND;
dbms_output.put_line(EMP_INFO.empno);
END LOOP;
close M_CURSOR;
end;
首先我们声明了一个游标和一个记录,开启游标以后,我们循环的把游标里的数据放入记录中,并在屏幕中打印出empno,直至游标结尾。
当我们使用for循环就不用那么麻烦了。
create or replace procedure demo14
is
CURSOR M_CURSOR IS
select * from emp;
begin
FOR EMP_INFO IN M_CURSOR
LOOP
dbms_output.put_line(EMP_INFO.empno);
END LOOP;
end;
我们还可以直接写select语句,但是那样显得不那么规范。
create or replace procedure demo13
is
begin
FOR var IN (select * from emp)
LOOP
dbms_output.put_line(var.empno);
END LOOP;
end;
在使用for循环时,我们可以用标签来给每个for循环命名以方便后期维护代码,