首页 > 代码库 > Oracle学习笔记(十一)

Oracle学习笔记(十一)

例外:
例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性.


例外分为:
系统例外
自定义例外

系统例外分为:
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;

Oracle学习笔记(十一)