例外:
    例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性.
例外分为:
系统例外
自定义例外
系统例外分为:
No_data_found(没有找到数据)、
Too_many_rows(select ... into 语句匹配多个行)、
Zero_Divide(被零除)、
Value_error(算数或转换错误,负数不能在实数范围开平方,abc不能转换成123)、
Timeout_on_resource(在等待资源时发生超时(分布式数据库))
No_data_found
组函数使用这个Exception无效,默认组函数在没有记录时会有默认的返回值 如count会返回0,max、min、avg等会返回空,这样的话是不会触发异常的
事例一:
--没有找到数据
set serveroutput on
declare
   pename emp.ename%type;
begin
     --查询员工号是1234的员工姓名
     select ename into pename from emp where empno=1234;
exception
    when no_data_found then 
    DBMS_OUTPUT.PUT_LINE(‘没有找到该员工‘);
    when others then
    DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/
事例二:
--匹配多个行
set serveroutput on
declare
   pename emp.ename%type;
begin
     --查询所有10号部门的员工姓名
     select ename into pename from emp where deptno=10;
exception
    when too_many_rows then 
    DBMS_OUTPUT.PUT_LINE(‘select...into匹配了多个行‘);
    when others then
    DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/
事例三:
--被零除
set serveroutput on
declare
  --定义一个基本变量
  pnum number;
begin
      pnum :=1/0;
exception
    when zero_divide then 
    DBMS_OUTPUT.PUT_LINE(‘1:0不能做除数‘);
    DBMS_OUTPUT.PUT_LINE(‘2:0不能做除数‘);
    when others then
    DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/
例外四:
-----value_error算数或转换错误
set serveroutput on
declare
  --定义一个基本变量
  pnum number;
begin
      pnum :=‘abc‘;
exception
    when value_error then 
    DBMS_OUTPUT.PUT_LINE(‘算数或者转换错误‘);
    when others then
    DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/
自定义例外
(1)定义变量,类型是Exception
(2)使用raise抛出自定义例外
事例:
set serveroutput on
declare
  cursor cemp is select ename from emp where deptno=50;
  --定义一个基本变量
  pename emp.ename%type;
  --自定义例外
   no_emp_found exception;
begin
        open cemp;
       --取出一条记录
        fetch cemp into pename;          
        if cemp%notfound then
	--抛出例外
	raise no_emp_found;
	end if;
	--关闭游标
	--oralce自动启动进程监视器pmon(process monition)
        close cemp;
exception
    when no_emp_found then 
    DBMS_OUTPUT.PUT_LINE(‘没有找到员工‘);
    when others then
    DBMS_OUTPUT.PUT_LINE(‘其他例外‘);
end;
/
PL/SQL程序设计综合案例
程序设计方法
瀑布模型
  需求分析
  设计
    概要设计
    详细设计
  编码
  测试
  部署
  运营
  思考:所需要的SQl语句和变量
         变量:1、初始值是多少
	      2、最终值如何得到
    综合案例1
		统计每年入职的员工人数
		 Total     1980        1981     1982     1987
		======== =======  ==========  ======== =========
		    14         1          10         1        2
注意:员工的入职年份已知
	   方法一(函数方式):
	         select count(*) Total,
		        sum(decode(to_char(hiredate,‘YYYY‘),‘1980‘,1,0)) "1980",
			sum(decode(to_char(hiredate,‘YYYY‘),‘1981‘,1,0)) "1981",
			sum(decode(to_char(hiredate,‘YYYY‘),‘1982‘,1,0)) "1982",
			sum(decode(to_char(hiredate,‘YYYY‘),‘1987‘,1,0)) "1987"
	         from emp;
          
	   /*
	   SQL语句
	   select to_char(hiredate,‘yyyy‘) from emp;
	   --->光标--->循环--->退出条件:notfound
	   变量:1.初始值2.如何得到
	   每年入职的员工人数:
	   count80 number:=0;
	   count81 number:=0;
	   count82 number:=0;
	   count87 number:=0;
	   */
	   PL/SQL开发:
          
	   set serveroutput on
           declare 
	   --定义光标
	   cursor cemp is select to_char(hiredate,‘yyyy‘) from emp;
           phiredate varchar2(4);
	   --每年入职的员工人数
           count80 number:=0;
	   count81 number:=0;
	   count82 number:=0;
	   count87 number:=0;
	   begin
              --打开光标
	      open cemp;
	        loop
                    --取出一个员工的入职年份
		    fetch cemp into phiredate;
		    exit when cemp%notfound;
		    --判断入职年份
		    if phiredate= ‘1980‘ then count80:=count80+1;
		    elsif phiredate=‘1981‘ then count81:=count81+1;
                    elsif phiredate=‘1982‘ then count82:=count82+1;
		    else count87:=count87+1;
                    end if;
		end loop;
		 --关闭光标
	         close cemp;
                 --输出结果
		 dbms_output.put_line(‘Total:‘||‘  ‘||(count80+count81+count82+count87));
		 dbms_output.put_line(‘1980:‘||‘   ‘||count80);
		 dbms_output.put_line(‘1981:‘||‘   ‘||count81);
                 dbms_output.put_line(‘1982:‘||‘   ‘||count82);
                 dbms_output.put_line(‘1987:‘||‘   ‘||count87);
           end;
           /
    综合案例2
        为员工涨工资.从最低工资涨起没人涨10%,但工资总额不能超过5万元,请计算涨工资的人数和涨工资后的工资总额,并输出涨工资人数及工资总额
	SQl语句
	select empno,sal from emp order by sal;
	-->光标-->循环-->退出条件:1、工资总额>5W 2、%notfound
	变量:1、初始值 2、如何得到
	涨工资的人数:
	countEmp number := 0;
	涨工资后的工资总额:
	salTotal number;
	1、select sum(sal) into salTotal from emp;
	2、涨后的工资总额=涨前的工资总额 + sal *0.1
        
         PL/SQL开发:
	 set serveroutput on
           declare 
	   --定义光标
	   cursor cemp is select empno,sal from emp order by sal;
	   pempno emp.empno%type;
           psal   emp.sal%type;
	   --涨工资的人数
           countEmp number:=0;
	   --涨后的工资总额
	   salTotal number;
	   begin
              --得到工资总额的初始值
	      select sum(sal) into salTotal from emp;
              --打开光标
                open cemp;
           loop
              --1、工资总额>5W
	      exit when salTotal > 50000;
	      --取一个员工涨工资
	      fetch cemp into pempno,psal;
	      --2、%notfound
              exit when cemp%notfound;
	      if (salTotal + psal*0.1) > 50000         
	      then dbms_output.put_line(‘超额不能涨工资了‘);
	       --涨工资
	       else update emp set sal=sal*1.1 where empno=pempno;
	       --人数+1
	       countEmp:=countEmp+1;
	       --2、涨后的工资总额=涨前的工资总额+sal*0.1
	       salTotal:=salTotal+psal*0.1; 
	       end if;
	     end loop;
	      --关闭光标
		close cemp;
		commit;
		--打印结果
		 dbms_output.put_line(‘涨薪水人数:‘||‘  ‘||countEmp);
		 dbms_output.put_line(‘涨后的工资总额:‘||‘   ‘||salTotal);
           end;
           /
    综合案例3
        用PL/SQL语言编写一程序,实现按部门分段(6000以上、(6000,3000)、3000元以下)统计各工资段的职工人数、以及各部门的工资总额(工资总额中不包括奖金)
	建立一张表
	    create table msg(
	       deptno number,
	       count1 number,
	       count2 number,
               count3 number,
               saltotal number
	    );
	 分析:
	    SQl语句
	      1、有哪些部门
	       select deptno from dept;
	       -->光标-->循环-->退出条件:1、工资总额>5W 2、%notfound
              2、部门中员工的薪水
	      select sal from emp where deptno=? -->带一个参数的光标-->循环-->退出条件:notfound(=true)
	变量:1、初始值 2、如何得到
	每个段的员工人数:
	count1 number := 0;
        count2 number := 0;
	count3 number := 0;
	每个部门的工资总额:
	salTotal number;
	1、select sum(sal) into salTotal from emp where deptno=???;
	2、累加(优越)
    PL/SQL开发:
	set serveroutput on
        declare 
	   --部门的光标
	   cursor cdept is select deptno from dept;
	   pdeptno dept.deptno%type;
           --部门中员工的光标
	   cursor cemp(dno number) is select sal from emp where deptno=dno;
           psal   emp.sal%type;
           --每个段的员工人数:
	    count1 number;
	    count2 number;
	    count3 number;
          
	   --每个部门的工资总额:
	   salTotal number;
	   begin
              --打开部门的光标
               open cdept;
           loop
	      --取一个员工涨工资
	      fetch cdept into pdeptno;
	      exit when cdept%notfound;
           
            --初始化的工作
	    count1:=0;
            count2:=0;
	    count3:=0;
	    --得到部门的工资总额
	    --1、select sum(sal) into salTotal from emp where deptno=???
            select sum(sal) into salTotal from emp where deptno=pdeptno;
 
		     --取部门中员工的薪水
		      open cemp(pdeptno);
		      loop
			       --取一个员工的薪水
			       fetch cemp into psal;
			       exit when cemp%notfound;
			       --判断薪水的范围
			       if psal<3000 then 
			                          count1:=count1+1;
				  elsif psal>=3000 and psal<6000 then 
				                  count2:=count2+1;
				  else  
				                   count3:=count3+1;
				end if;
		        end loop;
	      --关闭部门光标
	      close cemp;
	      --保存当前部门的结果
              insert into msg values(pdeptno,count1,count2,count3,nvl(salTotal,0));
	      end loop;
	    commit;
	      dbms_output.put_line(‘统计完成!!‘);
           end;
           /
  
       查看结果:
       select * from msg;
  综合案例4
          用PL/SQL语言编写一个程序.按系(系名)分段统计(成绩小于60分,60-85分,85分以上)"大学物理"课程各分数段的学生人数,及各系学生的平均成绩.
	  (多表查询和子查询)
	  脚本student.sql
	  drop table sc;
	  drop table course;
          drop table student;
	  drop table teacher;
          drop table dep;
	  create table dep(
	     dno number(2),
	     dname  varchar2(30),
	     director number(4),
	     tel varchar(8)
	  );
	  create table teacher(
	     tno number(4),
	     tname  varchar2(10),
	     title  varchar2(20),
	     hiredate date,
	     sal number(7,2),
	     bonus number(7,2),
	     mgr number(4),
	     deptno number(2)
	  );
	  create table student(
	     sno number(6),
	     sname  varchar2(8),
	     sex  varchar2(2),
	     birth  date,
	     passwd varchar2(8),
	     dno number(2)
	  );
	  create table course(
	     cno varchar2(8),
	     cname  varchar2(20),
	     credit  number(1),
	     ctime  number(2),
	     quota  number(3)
	  );
	  create table sc(
	     sno number(6),
	     cno varchar2(8),
	     grade number(3)
	  );
alter table dep add(constraint pk_deptno primary key(dno));
alter table dep add(constraint dno_number_check check(dno>=10 and dno<=50));
alter table dep modify(tel default 62795032);
alter table student add(constraint pk_sno primary key(sno));
alter table student add(constraint sex_check check(sex=‘男‘ or sex=‘女‘));
alter table student modify(birth default sysdate);
alter table course add(constraint pk_cno primary key(cno));
alter table sc add(constraint pk_key primary key(cno,sno));
alter table teacher add(constraint pk_tno primary key(tno));
alter table sc add(foreign key(cno) references course(cno));
alter table sc add(foreign key(sno) references student(sno));
alter table student add(foreign key(dno) references dep(dno));
alter table teacher add(foreign key(deptno) references dep(dno));
insert into dep values(10,‘计算机学院‘,9469,‘62785234‘);
insert into dep values(20,‘自动化学院‘,9581,‘62775234‘);
insert into dep values(30,‘无线电学院‘,9791,‘62778932‘);
insert into dep values(40,‘信息管理学院‘,9611,‘62785520‘);
insert into dep values(50,‘微纳电子学院‘,2031,‘62797686‘);
insert into teacher values(9468,‘CHARLES‘,‘PROFESSOR‘,‘17-Dec-17‘,8000,1000,null,10);
insert into teacher values(9469,‘SMITH‘,‘PROFESSOR‘,‘17-Dec-17‘,5000,1000,9468,10);
insert into teacher values(9470,‘ALLEN‘,‘ASSOCIATE PROFESSOR‘,‘20-Feb-16‘,4200,500,9469,10);
insert into teacher values(9471,‘WARD‘,‘LECTURER‘,‘22-Feb-17‘,3000,300,9469,10);
insert into teacher values(9581,‘JONES‘,‘PROFESSOR‘,‘2-Apr-2016‘,6500,1000,9468,20);
insert into teacher values(9582,‘MARTIN‘,‘ASSOCIATE PROFESSOR‘,‘28-Sep-2018‘,4000,800,9581,20);
insert into teacher values(9583,‘BLAKE‘,‘LECTURER‘,‘1-May -2019‘,3000,300,9581,20);
insert into teacher values(9791,‘CLAKE‘,‘PROFESSOR‘,‘9-Jun-2016‘,5500,null,9468,30);
insert into teacher values(9792,‘SCOTT‘,‘ASSOCIATE PROFESSOR‘,‘09-Dec-17‘,4500,null,9791,30);
insert into teacher values(9793,‘BAGGY‘,‘LECTURER‘,‘17-Nov-2017‘,3000,null,9791,30);
insert into teacher values(9611,‘TURNER‘,‘PROFESSOR‘,‘8-Sep-2018‘,6000,1000,9468,40);
insert into teacher values(9612,‘ADAMS‘,‘ASSOCIATE PROFESSOR‘,‘12-Jan-17‘,4800,800,9611,40);
insert into teacher values(9613,‘JAMES‘,‘LECTURER‘,‘3-Dec-19‘,2800,200,9611,40);
insert into teacher values(2031,‘FORD‘,‘PROFESSOR‘,‘3-Dec-18‘,5500,null,9468,50);
insert into teacher values(2032,‘MILLER‘,‘ASSOCIATE PROFESSOR‘,‘23-Jan-2018‘,4300,null,2031,50);
insert into teacher values(2033,‘MIGEAL‘,‘LECTURER‘,‘23-Jan-2019‘,2900,null,2031,50);
insert into teacher values(2034,‘PEGGY‘,‘LECTURER‘,‘23-Jan-2020‘,2800,null,2031,50);
更改格式
alter session set nls_date_language=‘AMERICAN‘;
19-JUN-01
保存数据的表格
create table msg1(
     coursename varchar2(20),
     dname varchar2(20),
     count1  number,
     count2  number,
     count3  number,
     avggrade number
);
SQL语句
1、得到有哪些系
   select dno,dname from dep;
   -->光标-->循环-->退出条件:notfound
2、得到系中,选修了"大学物理" 课程学生的成绩
  select grade from sc where cno=(select cno from course where cname=‘大学物理‘) and sno in (select sno from student where dno=??);
  -->带参数的光标-->循环-->退出条件:notfound
变量:1、初始值 2、如何得到
每个分数段的人数
count1 number;
count2 number;
count3 number;
每个系选修了"大学物理"学生的平均成绩
avggrade number;
1、算数运算
2、select avg(grade) into avggrade from sc where cno=(select cno from course where cname=‘大学物理‘) and sno in (select sno from student where dno=??);
PL/SQL开发:
	set serveroutput on
        declare 
	   --系的光标
	   cursor cdept is select dno,dname from dep;
	   pdno dep.dno%type;
	   pdname dep.dname%type;
           --成绩光标
	   cursor cgrade(coursename varchar2,depno number) is  select grade from sc where 
	   cno=(select cno from course where cname=coursename) and sno in (select sno from student where dno=depno);
	   pgrade sc.grade%type;
           --每个分数段的人数:
	    count1 number;count2 number;count3 number;
          
	   --每个系选修了"大学物理"学生的平均成绩:
	   avggrade number;
           --课程名称
	   pcourseName varchar2(20):=‘大学物理‘;
	
	   begin
              --打开部门的光标
               open cdept;
           loop
	      --取一个系的信息
	      fetch cdept into pdno,pdname;
	      exit when cdept%notfound;
    
            --初始化的工作
	     count1:=0;count2:=0;count3:=0;
                 
	     --系的平均成绩
             select avg(grade) into avggrade from sc 
	     where cno=(select cno from course where cname=pcourseName) 
	     and sno in (select sno from student where dno=pdno);
	      
	      --取系中,选修了大学物理的学生成绩
	      open cgrade(pcourseName,pdno);
	      loop
	         --取一个学生的成绩
		 fetch cgrade into pgrade;
                 exit when cgrade%notfound;
                              --判断成绩的范围
			       if pgrade<60 then 
			          count1:=count1+1;     
			       elsif pgrade>=60 and pgrade<85 then 
			           count2:=count2+1;     
			       else  
			           count3:=count3+1;     
			       end if ;    
	        end loop;
                close cgrade;
             --保存当前部门的结果
              insert into msg1 values(pcourseName,pdname,count1,count2,count3,avggrade);
	      end loop;
	      close cdept;
	     
	    commit;
	      dbms_output.put_line(‘统计完成!!‘);
           end;
           /
select * from msg1;
原文:http://www.cnblogs.com/liuyangfirst/p/6418580.html