ORACLE pl/sql自定义函数、存储过程

ORACLE pl/sql自定义函数、存储过程

2019-03-26

实验六、七 PL/SQL编程(2)

目的和要求:

1.​ 掌握存储过程和函数的使用
2.​ 掌握游标的使用
3.​ 掌握程序包的使用
4.​ 掌握触发器的使用

实验内容:

SCOTT用户拥有DEPT、EMP、SALGRADE表对象,其中,
DEPT是部门信息表,包括:部门编号、部门名称、部门地址三个属性,即DEPT(DEPTNO,DNAME,LOC)。
EMP是员工信息表,包括:员工编号、员工姓名、职位、上级领导、雇用时间、薪金、佣金、所属部门编号八个属性,即EMP(EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)。
SALGRADE是工资等级表,包括:工资等级、最低工资、最高工资三个属性,即SALGRADE(GRADE,LOSAL,HISAL)。

set serveroutput on
describe emp;
1.​ 使用异常编写一个PL/SQL程序来检查职工号为7369的职工的奖金,如果没有奖金的话则显示出错信息。

参考答案(仅为参考,有些并不可以直接执行):
declare
comm_error exception;
v_comm emp.comm%type;
begin
select comm into v_comm from emp where empno=‘7369’;
if v_comm=0 or v_comm is null then
raise comm_error;
end if;
exception
when NO_DATA_FOUND then
dbms_output.put_line(‘无7369职工!’);
when comm_error then
dbms_output.put_line(‘无佣金!’);
end;
/体会预定义异常、非预定义异常、用户自定义异常的使用。

declare
 comm_error exception;
 v_comm emp.comm%type;
begin
 select comm into v_comm from emp where empno=7369;
 if v_comm=0 or v_comm is null then
  raise comm_error;
 end if;

 exception
 when NO_DATA_FOUND then
  dbms_output.put_line('查无此人');
 when comm_error then
  dbms_output.put_line('无奖金');

end;
2.​ 编写一个函数来找出职工工资数额的信息,该函数还可以接受职工的号码。

create or replace function return_sal (eno scott.emp.empno%type)
return number
is
v_sal scott.emp.sal%type;
begin
select sal into v_sal from scott.emp where empno=eno;
return v_sal;
exception
when NO_DATA_FOUND then
dbms_output.put_line(‘无此职工!’);
end;
/
调用
declare
v_sal number(7,2);
begin
v_sal :=return_sal(7369);
dbms_output.put_line(v_sal);
end;
/

create or replace function return_sal (eno emp.empno%type)
return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=eno;
return v_sal;
exception
when NO_DATA_FOUND then
dbms_output.put_line('无此职工!');
end;
/
调用
declare
v_sal number(7,2);
begin
v_sal :=return_sal(7369);
dbms_output.put_line(v_sal);
end;
/
3.​ 编写一个函数来找出职工的经理信息,该函数还可以接受职工的姓名。
create or replace function return_mgr (nowname emp.ename%type)
return number
is
v_mgr emp.mgr%type;
begin
select mgr into v_mgr from emp where ename=nowname;
return v_mgr;
exception
when NO_DATA_FOUND then
dbms_output.put_line('无此职工!');
end;
/
调用
declare
v_mgr number(4);
begin
v_mgr :=return_mgr('CLARK');
dbms_output.put_line(v_mgr);
end;
/
4.​ 编写一个函数,该函数可以根据接受职工的号码。来返回ENAME、SAL、DEPTNO信息。

create or replace function ret_info(empno emp.empno%type, sal out emp.sal%type, deptno out emp.deptno%type)
return emp.ename%type
is
v_name emp.ename%type;
begin
select ename, sal, deptno into v_name, sal, deptno from emp where empno=empno;
return v_name;
end ;
/
调用
declare
v_name emp.ename%type;
v_sal emp.sal%type;
v_deptno emp.deptno%type;
begin
v_name:=ret_info(&empno, v_sal, v_deptno);
dbms_output.put_line(v_name||v_deptno||v_sal);
end;

//示例程序中,line6,where empno=empno:实际返回的行数超出请求的行数。更名即可。
create or replace function ret_info(empo emp.empno%type, sal out emp.sal%type, deptno out emp.deptno%type)
return emp.ename%type
is
v_name emp.ename%type;
begin
select ename, sal, deptno into v_name, sal, deptno from emp where empno=empo;
return v_name;
end ;
/
5.​ /

接4,调用函数

declare
v_name emp.ename%type;
v_sal emp.sal%type;
v_deptno emp.deptno%type;
v_eno emp.empno%type;
begin
v_eno:=&v_eno;
v_name:=ret_info(v_eno, v_sal, v_deptno);
dbms_output.put_line(v_name||' '||v_deptno||' '||v_sal);
end;
/

ORACLE pl/sql自定义函数、存储过程_第1张图片

6.​ 编写一个函数,该函数可以根据接受的职工姓名,来确定该职工的年收入信息。如果有两个或以上重名职工的话将出现错误信息。
//注意输入字符串的格式:'###'

create or replace function return_annualSalary(nowname emp.ename%type)
return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where ename=nowname;
return 12*v_sal;
exception
when NO_DATA_FOUND then
dbms_output.put_line('无此职工!');
end;
/
调用
declare
v_sal emp.sal%type;
begin
v_sal:=return_annualSalary(&nowname);
dbms_output.put_line(v_sal);
end;
/

ORACLE pl/sql自定义函数、存储过程_第2张图片
ORACLE pl/sql自定义函数、存储过程_第3张图片

7.​ 编写一个存储过程来显示出DEPT表的所有信息。
create or replace procedure show_dept is
begin
  dbms_output.put_line('---------------------------------------');
  for dept_i in (select * from dept)
    loop
      dbms_output.put_line(dept_i.deptno||' '||dept_i.dname||' '||dept_i.loc);
    end loop;
  dbms_output.put_line('---------------------------------------');
end;
/

begin
  show_dept;
end;
/

ORACLE pl/sql自定义函数、存储过程_第4张图片

8.​ 编写一个存储过程来显示出EMP表信息,而且该过程可以接受DEPTNO列的数据。

create or replace procedure show_emp (deptno in emp.deptno%type)
is
cursor emp_cursor is select * from emp;
begin
for r in emp_cursor loop
dbms_output.put(r.empno || ‘’);
dbms_output.put(r.ename || ‘’);
dbms_otuput.put(r.job || ‘’);
dbms_output.put(r.mgr || ‘’);
dbms_output.put(r.hiredate || ‘’);
dbms_output.put(r.sal || ‘’);
dbms_output.put(r.comm || ‘’);
dbms_output.put_line(r.deptno);
end loop;
end;
/
过程调用
set serveroutput on
declare
deptno emp.deptno%type:=7369;
begin
show_emp(deptno);
end;
/

create or replace procedure show_emp (dno in emp.deptno%type)
is
  cursor emp_cursor is select * from emp where emp.deptno=dno;
begin
  dbms_output.put_line('---------------------------------------');
  for r in emp_cursor loop
    dbms_output.put_line(r.empno || ' '|| r.ename || ' '||r.job || ' '||r.mgr || ' '||r.hiredate || ' '||r.sal || ' '||r.comm || ' '||r.deptno);
  end loop;
  dbms_output.put_line('---------------------------------------');
end;
/

begin  show_emp(10);
end;
/

ORACLE pl/sql自定义函数、存储过程_第5张图片

ORACLE pl/sql自定义函数、存储过程_第6张图片

9.​ 根据工作类别,编写一个存储过程来找出工资数额最高的职工信息。

(此题目应该理解为,根据部门编号,找出每个部门中工资数额最高的职工信息,需要使用游标实现)

This is an unsuccessful try:

select max(sal) from emp group by deptno;

ORACLE pl/sql自定义函数、存储过程_第7张图片
Another try:
ORACLE pl/sql自定义函数、存储过程_第8张图片
Try again:

create or replace procedure show_mx_sal is
  d_d dept.deptno%type;
  e_sal emp.sal%type;
  cursor cr_dno is
    select distinct deptno from dept;
begin
  dbms_output.put_line('---------------------------------------');
  for i in cr_dno 
    loop   
      d_d:= i.deptno;
      select max(sal) into e_sal from emp where emp.deptno=d_d;
      dbms_output.put_line('部门'||d_d||'的最高工资数额是:'||e_sal); 
    end loop;
  dbms_output.put_line('---------------------------------------');
end;
/

begin
  show_mx_sal;  
end;

/

ORACLE pl/sql自定义函数、存储过程_第9张图片


create or replace procedure show_mx_sal is
  d_d dept.deptno%type;
  e_sal emp.sal%type;
  cursor cr_dno is
    select distinct deptno from dept;
begin

  dbms_output.put_line('---------------------------------------');
  for i in cr_dno 
    loop   
      d_d:= i.deptno;
      select max(sal) into e_sal from emp where emp.deptno=d_d;
      dbms_output.put_line('**部门'||d_d||'的最高工资数额是:'||e_sal);
      dbms_output.put_line('**以下为工资最高员工的信息:');
      for j in (select * from emp where sal=e_sal and deptno=d_d)
        loop
          dbms_output.put_line(' 员工编号'||j.empno||' 姓名'||j.ename||' 工资'||j.sal||' 工作'||j.job||' 部门'||j.deptno);
        end loop;
      dbms_output.put_line('**************************** ');
    end loop;

  dbms_output.put_line('---------------------------------------');

end;
/



begin
  show_mx_sal;
end;

/

ORACLE pl/sql自定义函数、存储过程_第10张图片

10.​ 编写一个触发器,它能够自动计算所有职工的总收入,并且在DEPT表中的一个专门的列中保存它们(在DEPT表中增加一个名为TOT_SAL的列)。

alter table DEPT
add (TOT_SAL number);
CREATE OR REPLACE TRIGGER tr_add_sal
After UPDATE or INSERT or DELETE
ON emp
Is
Cursor c1 is select distinct deptno from emp;
v_tot_sal emp.sal%Type;
Begin
For i in c1 loop
Select sum(sal) into v_tot_sal from emp where deptno=i.deptno;
Update dept set tot_sal=v_tot_sal where deptno= i.deptno;
End loop;
End;
ORACLE pl/sql自定义函数、存储过程_第11张图片

11.​ 在EMP_DEPT视图上编写一个触发器,该触发器可以检查SALGRADE表中的收入范围,如果任何一个更新或者插入的值超出9999的话则出现错误信息。

2019-04-02

create view EMP_DEPT as
select empno,ename,job,sal,dname
from emp,dept
where emp.deptno=dept.deptno;
--创建视图EMP_DEPT,信息来自EMP表和DEPT表。

insert into EMP_DEPT(empno,ename,job,sal,dname)
values (1246,'Anonym','MANAGER',1500,'SALAS');
--合法的更新

insert into EMP_DEPT(empno,ename,job,sal,dname)
values (1247,'Anonym','MANAGER',-1,'SALAS');
--超出下界的更新

insert into EMP_DEPT(empno,ename,job,sal,dname)
values (1248,'Anonym','MANAGER',10000,'SALAS');
--超出上界的更新

create or replace trigger tr_check_sal
instead of
insert or update on EMP_DEPT
for each row
declare
   tmp_deptno emp.deptno%type;
   sal_error1 exception;
   sal_error2 exception;
begin
   if :new.sal>9999 then
     raise sal_error1;
   end if;
   if :new.sal<=0 then
     raise sal_error2;
   end if;
   
   insert into emp(empno,ename,job,sal)
   values(:new.empno,:new.ename,:new.job,:new.sal);
   
   select deptno into tmp_deptno
   from dept
   where dname= :new.dname;
   
   update emp
   set deptno=tmp_deptno
   where empno= :new.empno;
   --由于是insert或update一个部门名,而这个部门名是已经存在了的,所以无需改动dept表,但可能需要更新emp表相应empno的deptno信息(update时候如果部门更改则需要更新)。
   
   exception
     when sal_error1 then
     dbms_output.put_line('新增薪金超出上界');
     when sal_error2 then
     dbms_output.put_line('新增薪金超出下界');
end;
/

ORACLE pl/sql自定义函数、存储过程_第12张图片
由于EMP_DEPT视图涉及两个表,不能直接添加纪录:
ORACLE pl/sql自定义函数、存储过程_第13张图片
ORACLE pl/sql自定义函数、存储过程_第14张图片
在这里插入图片描述

**

以下未解——

**
ORACLE pl/sql自定义函数、存储过程_第15张图片
???已抛出异常,还创建1行??
ORACLE pl/sql自定义函数、存储过程_第16张图片
ORACLE pl/sql自定义函数、存储过程_第17张图片
视图empno无新增1247、1248,表empno也无1247、1248,
所以创建了哪一行呢?

你可能感兴趣的:(Others)