(一)之基本数据类型、程序结构
PL/SQL是一种高效的事物处理语言,它具有如下优点
1、支持SQL
2、支持面向对象的编程方法
3、更好的性能和更高的效率
4、编写方便
5、与Oracle高度集成
6、安全性好
一、PL/SQL变量和基本数据类型
1、PL/SQL变量的定义
基本数据类型变量的定义方法如下:
变量名 类型标识符 [:= 值];
如: Str varchar2[100] := '中国';
也可以使用关键字default来代替赋值符。
str varchar2[100] default '中国';
注意:赋值符合中的冒号和等号是不能分开的;
2、基本数据类型

三、PL/SQL程序的结构
首先看一个简单的例子:以下是一个完整的PL/SQL程序,用于求方程ax²+bx+c=0的根
- declare
- a int := 3;
- b int := 8;
- c int := 2;
- x1 number(8,2);
- x2 number(8,2);
- t number(8,2);
- error exception;
- begin
- t := b**2-4*a*c;
- if t<0 then
- raise error;
- end if;
- x1 := (-b+sqrt(t)/(2*a));
- x2 := (b+sqrt(t)/(2*a));
- dbms_output.put_line('x1='||x1);
- dbms_output.put_line('x2='||x2);
- exception
- when error then dbms_output.put_line('此方程无解');
- end;
从上面可以看出一个PL/SQL程序分为3个部分:
1)、定义部分。在PL/SQL程序中,所用到的常量、变量、游标等必须在这一部分中定义。
但是这个部分的变量定义不能使用逗号分隔的办法来同时声明多个变量。
分号是每个变量声明和语句的结束符。
如果一个PL/SQL程序中没有变量需要定义,那么这个部分是可以去掉的。
2)、执行部分。这个部分是PL/SQL程序中的核心部分,包括赋值语句、对数据库的操作语句和流程控制语句等,构成 PL/SQL程序的基本块结构。
执行部分至少有一个可执行语句。
3)异常处理部分。当程序检测到错误情况时即产生异常。由exception标识的部分来处理程序过程产生的异常。
所以一个PL/SQL程序的基本结构可以是以下结构:
Declare
定义部分
Begin
执行部分
Exception
异常处理部分
End;
(二)之程序流程
一、PL/SQL程序流程控制

上面的结构与其他的高级语言程序一样,就不做介绍了。
下就条件结构和循环结构说明。
1)IF条件控制句
1.1 IF...THEN语句
其语法是:
IF p THEN
基本语句段;
END IF;
例如:
- declare
- flag1 integer := 1;
- flag2 integer := 2;
- begin
- if flag1 < flag 2 then
- dbms_output.put_line('Flag1<flag2');
- end if;
- end;
注意:上面的IF 与END IF必须成对出现
1.2 IF...THEN...ELSE语句
该语句用于需要在两个语句段之间做出选择时。其语法如下:
IF P THEN
语句段1;
ELSE
语句段2;
EDN IF;
在该语句中,如果p的值为true,则执行语句段1,否则执行语句段2;实例:
- declare
- flag1 integer := 5;
- flag2 integer := 8;
- begin
- if flag1 <flag2 then
- dbms_output.put_line('flag1<flag2');
- else
- dbms_output.put_line('flag1>flag2');
- end if;
- end;
1.3 IF...THEN...ELSIF语句
该语句用于在三个或者三个以上的语句段之间做出选择。其语法段为:
IF P1 THEN
语句段1;
ELSIF P2 THEN
语句段2;
ELSE
语句段3;
END IF;
实例:
- declare
- grade number := 98;
- results varchar2(10);
- begin
- if grade >=90 then
- results := '优';
- elsif grade >= 80 then
- results :='良';
- elsif grade >=70 then
- results :='中';
- elsif grade >= 60 then
- results :='及格';
- else
- results :='差';
- end if;
- dbms_output.put_line(results);
- end;
1.4 CASE选择控制
该语句用于控制多分支选择功能。其实 IF...THEN...ELSIF语句也可以实现这个功能,但是非常的麻烦。其语法结构为:
CASE E
WHEN e1: THEN 语句段1;
WHEN e2: THEN 语句段2 ;
WHEN e3: THEN 语句段3;
....................
WHEN en: THEN 语句段n ;
END CASE;
实例:
- declare
- results varchar2(20) := 'B';
- grade varchar2(20);
- begin
- case results
- when 'A' then grade := '90-100';
- when 'B' then grade := '80-89';
- when 'C' then grade := '70-79';
- when 'D' then grade := '60-69';
- when 'E' then grade := '<60';
- else grade := '不存在这个成绩等级';
- end case;
- dbms_output.put_line(grade);
- end;
2)、循环控制
2.1 FOR...LOOP语句
该形式如下:
FOR I [REVERSE]IN lb..hb LOOP
语句段;
END LOOP;
其中,i为整型变量,一般称为循环计算器,lb和hb均为整型常量,分别代表了i的下限和上限,..为范围操作符。当没有使用参数REVERSE时,i的初值被设置为lb。实例:
- declare
- i int := 0;
- begin
- for i in 1..3 loop
- dbms_output.put_line('循环第'||to_char(i)||'次时'||to_char(i));
- end loop;
- end;
2.2 LOOP...EXIT循环控制
该语句用于控制死循环的。一般对于死循环的控制,有如下三种方式:
2.2.1 利用if语句
LOOP
语句段;
IF P THEN
EXIT;
END IF;
END LOOP;
实例:
- declare
- i int := 0;
- results integer := 0;
- begin
- loop
- results := results + i;
- if i = 10 then
- exit;
- end if;
- i : i+1;
- end loop;
- dbms_output.put_line('累加结果为:'||to_char(results));
- end;
2.2.2 利用EXIT...WHEN
LOOP
.........
EXIT WHEN e;
.............
END LOOP;
其中e为布尔表达式,如果e的值为true则循环退出,否则继续执行循环语句。实例:
- declare
- i int := 1;
- results integer := 0;
- begin
- loop
- results := results+i;
- exit when i = 10;
- i := i+1;
- end loop;
- dbms_output.put_line('累加结果为:'||to_char(results));
- end;
2.2.3: 利用标签
该语句的格式如下:
<<标签名>>
LOOP
.......
EXIT 标签名 WHEN e;
........
END LOOP;
当e为true时退出。注意,标签名必须在loop语句之前用“<<>>”定义实例:
- declare
- i integer := 1;
- results integer := 0;
- begin
- <<my_label>>
- loop
- results := results + i;
- exit my_label when i = 10;
- i := i+1;
- end loop;
- dbms_output.put_line('累加的结果为:'||to_char(results));
- end;
2.3 WHILE...LOOP循环控制
WHILE e LOOP
语句段;
END LOOP;
E为循环条件,当e的值为true时则执行循环体,否则退出循环。
实例:
- declare
- m integer := 100;
- n integer := 7;
- results integer;
- begin
- results := m;
- while results >=n loop
- results := results - n;
- end loop;
- dbms_output.put_line(to_char(m)||'除以'||to_char(n)||'的余数'||to_char(results));
- end;
二、在PL/SQL程序中调用SQL语句
实际上在PL/SQL程序中i调用SQL语句,对于不同的SQL语句调用的方法是不一样的。在这里介绍常用的 几种语句的调用方法。
2.1调用SELECT语句
在调用这个语句之间,应该定义一个变量用来存储SELECT语句产生的结果,而且 这个变量的结果要与SELECT之后的字段列表相一致。实例:
- declare
- temp_emp scott.emp%rowtype;
- begin
- select * into temp_emp from emp where empno=7369;
- dbms_output.put_line(to_char(temp_emp.empno||','||temp_emp.ename));
- end;
注意:这种变量只能是一条记录,否则就会出错。而且如果SELECT语句无返回结果,同样会报错。
2.2调用INSERT语句
这条语句可以直接调用。实例:
- declare
- empno emp.empno%type;
- ename emp.ename%type;
- job emp.job%type;
- mgr emp.mgr%type;
- hiredate emp.hiredate%type;
- sal emp.sal%type;
- comm emp.comm%type;
- deptno emp.deptno%type;
- begin
- empno := 6676;
- ename := 'LILY';
- job := 'CLERK';
- mgr := 7899;
- hiredate := to_date('1981-12-12','yyyy-mm-dd');
- sal := 999.00;
- comm := 433.00;
- deptno := 20;
- insert into emp values(empno,ename,job,mgr,hiredate,sal,comm,deptno);
- end;
2.3调用UPDATE语句
同样可以之间调用。实例:
- declare
- tempno scott.emp.empno%type;
- begin
- tempno := 7677;
- update emp set ename='AAA' where empno = tempno;
- end;
2.4调用DELETE语句
直接调用。实例:
- declare
- tempno scott.emp.empno%type;
- begin
- tempno := 7677;
- delete form emp where empno = tempno;
- end;
-
(三)之游标
游标是从数据库中提取出来一临时表的形式存放在内存中的数据。可以把游标看作是内存的SQL工作区域,游标名称相当于该区域的句柄。通过该句柄可以有效地控制游标,从而实现对数据的操作。所以对游标的操作实际上就是对数据库库的间接操作。
1.1游标的定义
定义游标的格式如下:
CURSOR 游标 IS SELECT 语句;
例如:把数据表中emp中部门号为20的员工定义为游标:
- CURSOR exce_emp is select * from scott.emp where deptno=20;
定义游标后,我们就可以使用游标了。但是要对游标进行操作我们必须先打开游标:
Open 游标名;
打开游标实际上是从数据表中读取数据的过程,在这个过程中主要完成两件事:
1、把select查询结果读入内存工作区中。
2、将游标指针定位在第一条记录。
游标在使用后,要关闭:close 游标名;
1.2利用fetch命令从游标中提取数据
我们定义游标并且打开游标后,就可以利用fetch命令从游标中提取数据。
FETCH 游标名 INTO变量名1,变量名2......
或者
FFETCJ 游标名 INTO 纪录型变量名;
FETCH命令首先将当前游标指针所指的行读出来并且置于相应的变量中,然后把游标指针移到下一行。所以FETCH命令每一个执行的时候,只能提取一行或者部分的数据。
实例:
- declare
- cursor exce_emp is select * from emp where empno=6676;
- var_exce_emp exce_emp%rowtype;
- begin
- open exce_emp;
- fetch exce_emp into var_exce_emp;
- dbms_output.put_line('提取的数据为:员工的姓名:'||var_exce_emp.ename||',员工的工作为:'||var_exce_emp.job);
- close exce_emp;
- end;
存在这样一种情况,如果游标指针已经指到了游标的末尾,那么FETCH命令将读不到数据了,所以应该有这样一种机制,这种机制可以测出游标是否已经指到了游标的末尾。这种机制就是游标的属性。
1.3游标的属性
游标有四个属性:%FOUND、%ISOPEN、%NOTFOUND、%ROWCOUNT。
下面就分别这四个属性介绍:
1.3.1%FOUND
该属性用于测试在自己所在语句之前的最后一个FETCH命令是否提取到了数据。如果能够提取到数据就返回true,否则返回false。但是如果一个游标还没有被打开就运用%FOUND,那么将会产生INVALID_CURSOR异常。
实例:
- declare
- cursor exce_emp is select empno,ename from emp where deptno=20;
- var_exce_emp exce_emp%rowtype;
- i int := 1;
- begin
- open exce_emp;
- loop
- fetch exce_emp into var_exce_emp;
- if exce_emp %found then
- dbms_output.put_line('第'||to_char(i)||'个员工的信息-------编号:'||var_exce_emp.empno||'员工姓名:'||var_exce_emp.ename);
- i := i+1;
- else
- exit;
- end if;
- end loop;
- close exce_emp;
- end;
1.3.2%ISOPEN
该属性主要用于测试游标是否已经打开。
实例:
- declare
- cursor exce_emp is select empno,ename from emp;
- var_exce_emp exce_emp%rowtype;
- begin
- if not exce_emp%isopen then
- dbms_output.put_line('游标没有打开');
- open exce_emp;
- else
- dbms_output.put_line('游标已经打开了');
- end if;
- end;
1.3.3%NOFOUND
该属性与%FOUND相反。这里就不做介绍了。
1.3.4%ROWCOUNT
当刚刚打开游标时,%ROWCOUNT的值为0。每运行一次FETCH命令,%ROWCOUNT的值就会自增1。因此%ROWCOUNT的值可以看着是游标中当前被读取了的记录的条数,即游标循环中处理的当前行数。如果一个有游标在打开之前调用%ROWCOUNT属性,就会产生异常INVALID_CURSOR。
实例:
- declare
- cursor exce_emp is empno,ename from emp where deptno=20;
- var_exce_emp exce_emp%rowtype;
- n int := 5;
- begin
- open exce_emp;
- loop
- fetch exce_emp into var_exce_emp;
- exit when exce_emp%notfound;
- dbms_output.put_line('员工号:'||var_exce_emp.empno||',员工姓名:'||var_exce_emp.ename);
- exit when exce_emp%rowcount=n;
- end loop;
- close exce_emp;
- end;
1.4隐式游标
上面介绍的都是显示游标。其实Oracle还默认了一种游标,这个游标就是隐式游标。其被定义为SQL。它同时也具有4个属性。如下:
- declare
- tempdeptno := 20;
- counts int := 0;
- begin
- update emp set job='CLERK' where deptno = tempdeptno;
- if sql%found then
- counts := sql%rowcount;
- end if;
- dbms_output.put_line('对'||to_char(counts)||'行语句做了修改');
- end;
注意:隐式游标时不需要打开和关闭的。
下面就显示游标和隐式游标做一个比较
