Oracle认识存储过程

第一个简单的存储过程

1.无参存储过程

[sql]  view plain  copy
  1. create or replace procedure proce_1  
  2. IS  
  3. BEGIN  
  4.   DBMS_OUTPUT.put_line('欢迎你'||USER);  
  5. END ;  

调用

[sql]  view plain  copy
  1. BEGIN  
  2.    proce_1 ;  
  3.   END ;  

                               2.带输入参数的存储过程


2.1使用标量变量作为输入参数

如下 使用标量变量作为输入参数,实现向部门表dept 增加信息

[sql]  view plain  copy
  1. CREATE OR REPLACE PROCEDURE add_dept(deptno dept.deptno%TYPE,dname dept.dname%TYPE,loc dept.loc%TYPE)  
  2.  IS  
  3.  BEGIN  
  4.    INSERT INTO DEPT VALUES(deptno,dname,loc);  
  5.    EXCEPTION  
  6.      WHEN DUP_VAL_ON_INDEX THEN  
  7.      dbms_output.put_line('主键冲突,重新指定主键值');  
  8.    END ;  

实现插入语句

[sql]  view plain  copy
  1. BEGIN   
  2.      add_dept(10,'zzz','zz');  
  3.      commit ;  
  4.      END ;  

检查 通过查看表 可以查看记录是否进去了。

2.2使用记录类型作为输入参数
如下 使用标量变量作为输入参数,实现向部门表dept 增加信息

 

[sql]  view plain  copy
  1. CREATE OR REPLACE PROCEDURE add_dept2(dept_record dept%ROWTYPE)  
  2.    IS  
  3.    BEGIN  
  4.      INSERT INTO dept  
  5.      VALUES(dept_record.deptno,dept_record.dname,dept_record.loc);  
  6.    EXCEPTION  
  7.    WHEN DUP_VAL_ON_INDEX THEN  
  8.    dbms_output.put_line('主键冲突,重新指定主键值');  
  9.      END ;    

调用:

[sql]  view plain  copy
  1. DECLARE  
  2.      dept_record dept%ROWTYPE;   
  3.     BEGIN  
  4.       dept_record.deptno:=&deptno;  
  5.       dept_record.dname:='&dname';  
  6.       dept_record.loc:='&loc';  
  7.       add_dept2(dept_record);  
  8.       END ;  
2.3 使用集合类型作为输入参数

第一步  

  基于部门dept表创建嵌套表类型

[sql]  view plain  copy
  1. --基于部门表dept创建嵌套表类型  
  2. --基于deptno列创建嵌套表类型  
  3. CREATE TYPE deptno_table_type IS TABLE OF NUMBER(2);  
  4. --基于dname列创建嵌套表类型  
  5. CREATE TYPE dname_table_type IS TABLE OF VARCHAR2(20);  
  6. --基于loc列创建嵌套表类型  
  7. CREATE TYPE loc_table_type IS TABLE OF VARCHAR2(20);  
第二步 

基于嵌套表类型创建存储过程

[sql]  view plain  copy
  1. CREATE OR REPLACE PROCEDURE add_dept3(deptno_table deptno_table_type,dname_table dname_table_type,loc_table loc_table_type)  
  2.  IS  
  3.  BEGIN  
  4.    FOR i IN 1..deptno_table.COUNT LOOP  
  5.      INSERT INTO dept  
  6.      VALUES(deptno_table(i),dname_table(i),loc_table(i));  
  7.      END LOOP ;  
  8.     EXCEPTION  
  9.       WHEN DUP_VAL_ON_INDEX THEN  
  10.      dbms_output.put_line('主键冲突,重新指定主键值');  
  11.      WHEN SUBSCRIPT_BEYOND_COUNT THEN  
  12.         dbms_output.put_line('部分集合的元素值不够');  
  13.    END ;  
第三步

[sql]  view plain  copy
  1. DECLARE  
  2.  deptno_table deptno_table_type ;  
  3.  dname_table  dname_table_type ;  
  4.  loc_table    loc_table_type ;  
  5.  BEGIN  
  6.    SELECT * BULK COLLECT INTO deptno_table,dname_table,loc_table FROM  dept ;  
  7.    FOR i IN 1..deptno_table.COUNT LOOP  
  8.      deptno_table(i):=deptno_table(i)+1;  
  9.      END LOOP ;  
  10.      add_dept3(deptno_table,dname_table,loc_table);  
  11.    END ;  

                                         3.带输出参数的存储过程

3.1   使用标量变量作为输出参数

使用标量变量作为输出参数,根据输入的部门号,输出当前部门信息

[sql]  view plain  copy
  1. CREATE OR REPLACE PROCEDURE get_dept(p_deptno dept.deptno%TYPE,dname OUT dept.dname%TYPE, loc OUT dept.loc%TYPE)  
  2. IS  
  3. BEGIN  
  4.   SELECT dname,loc into dname,loc FROM dept WHERE deptno=p_deptno ;  
  5.   EXCEPTION   
  6.     WHEN NO_DATA_FOUND THEN   
  7.     dbms_output.put_line('不存在该部门');  
  8.   END ;  

调用存储过程get_dept ;

[sql]  view plain  copy
  1. --调用存储过程get_dept   
  2.  DECLARE   
  3.  v_deptno dept.deptno%TYPE;  
  4.  v_dname dept.dname%TYPE;  
  5.  v_loc dept.loc%TYPE;  
  6.  BEGIN  
  7.    v_deptno:=&p_deptno ;  
  8.    get_dept(v_deptno,v_dname,v_loc);  
  9.    dbms_output.put_line('部门号: '||v_deptno||',部门号:'||v_dname||'位置:'||v_loc);  
  10.    END ;  

结果:

[plain]  view plain  copy
  1. 部门号: 10,部门号:ACCOUNTING位置:NEW YORK  


3.2 使用记录类型作为输出参数

[sql]  view plain  copy
  1. --使用记录类型作为输出参数  
  2.   
  3. CREATE OR REPLACE PROCEDURE get_dept2(p_deptno dept.deptno%TYPE,dept_record OUT dept%ROWTYPE)  
  4. IS  
  5. BEGIN  
  6.   SELECT * INTO dept_record   
  7.   FROM dept WHERE deptno=p_deptno ;  
  8.   EXCEPTION   
  9.     WHEN NO_DATA_FOUND THEN  
  10.       dbms_output.put_line('不存在该部门!');  
  11.   END ;  

调用存储过程get_dpet2

[sql]  view plain  copy
  1. -- 调用存储过程get_dept2  
  2. DECLARE   
  3. v_deptno dept.deptno%TYPE ;  
  4. dept_record dept%ROWTYPE ;  
  5. BEGIN  
  6.   v_deptno:=&p_deptno ;  
  7.   get_dept2(v_deptno,dept_record);  
  8.   dbms_output.put_line('部门号:'||dept_record.deptno||',部门名:'||dept_record.dname||'位置:'||dept_record.loc);  
  9.   END ;  

3.3 使用集合类型作为输出参数

[sql]  view plain  copy
  1.    CREATE OR REPLACE PROCEDURE  get_dept3(p_loc dept.loc%TYPE,deptno_table OUT deptno_table_type ,dname_table OUT dname_table_type)  
  2. IS  
  3. BEGIN  
  4.   SELECT deptno,dname BULK COLLECT INTO deptno_table,dname_table   
  5.   FROM dept WHERE LOWER(loc) =p_loc ;  
  6. EXCEPTION  
  7.   WHEN NO_DATA_FOUND THEN  
  8.   dbms_output.put_line('不存在该部门!');  
  9.   END ;   
调用

[sql]  view plain  copy
  1. --调用存储过程get_dept3  
  2.   
  3. DECLARE   
  4. v_loc dept.loc%TYPE;  
  5. deptno_table deptno_table_type;  
  6. dname_table dname_table_type ;  
  7. BEGIN  
  8.   v_loc:=LOWER('&p_loc');  
  9.   get_dept3(v_loc,deptno_table,dname_table);  
  10.   dbms_output.put_line('在'||v_loc||'的部门有:');  
  11.   FOR i IN 1..deptno_table.COUNT LOOP  
  12.     dbms_output.put_line('部门号:'||deptno_table(i)||  
  13.     ',部门名:'||dname_table(i));  
  14.     END LOOP ;  
  15.   END;  
结果:

[plain]  view plain  copy
  1. 在dallas的部门有:  
  2. 部门号:21,部门名:RESEARCH  
  3. 部门号:22,部门名:RESEARCH  
  4. 部门号:20,部门名:RESEARCH  

                                                 4.带输入/输出参数的存储过程


[sql]  view plain  copy
  1. CREATE OR REPLACE PROCEDURE add_sub(n1 IN OUT NUMBER ,n2 IN OUT NUMBER)  
  2. IS  
  3. BEGIN  
  4.   /**使用n1返回两数的和**/  
  5.   n1 :=n1+n2 ;  
  6.   /** 使用n2 返回两数的差  **/  
  7.   n2:=n1-2*n2 ;  
  8.   END ;  
  9.     

调用


[sql]  view plain  copy
  1. /**调用存储过程add_sub**/  
  2. DECLARE   
  3. num1 NUMBER:=&num1 ;  
  4. num2 NUMBER:=&num2 ;  
  5. BEGIN  
  6.   add_sub(num1,num2);  
  7.   dbms_output.put_line('和:'||num1||',差'||num2);  
  8.   END ;  

                                     5 补充学习

                             

存储过程中的AS/IS相当于PLSQL中的declare地方
--为指定员工  涨100块钱的工资,并且打印涨钱和涨后的薪水
create or replace procedure p2 (eno IN emp.empno%TYPE )
IS
beforesal  emp.sal%TYPE  ;
aftersal  emp.sal%TYPE  ;
BEGIN
select sal  into beforesal from emp  where empno=eno ;

dbms_output.put_line('涨工资之前'||beforesal);
update emp  set sal=sal+100  where empno =eno ;
select sal  into aftersal from emp  where empno=eno ;
dbms_output.put_line('涨工资之后'||aftersal);
EXCEPTION
WHEN  NO_DATA_FOUND  THEN 
dbms_output.put_line('没数据');
END ;
--查询某个员工姓名和月薪
create  or replace procedure queryinfo(pno emp.empno%TYPE, pname  OUT emp.ename%TYPE,psal OUT emp.sal%TYPE)
is
begin
select  ename,sal into pname ,psal from emp where empno=pno ;
dbms_output.put_line(pname||psal);
end ;

6 包头 包体   光标 

---思考 查询某个员工的所有信息  out太多?
---思考 查询某个部门下所有员工信息
在OUT参数中使用光标
申明包结构
包头
包体
包体需要实现包头中声明的所有方法

--声明包头
CREATE OR REPLACE PACKAGE MYPACKAGE 
AS
type  empcursor  is ref cursor ;
procedure  queryEmpList(dno IN NUMBER ,empList OUT empcursor );
--如果有其他存储过程可以继续添加
END MYPACKAGE ;
--声明包体
CREATE OR REPLACE
PACKAGE BODY MYPACKAGE AS
procedure queryEmpList(dno IN NUMBER ,empList OUT empcursor )AS
BEGIN
--TODO
--打开光标
 open empcursor for select * from emp where empno =dno ;
END queryEmpList ;
END MYPACKAGE ;






7维护存储过程

[sql]  view plain  copy
  1. /**维护存储过程**/  
  2. --1.删除存储过程  
  3. DROP PROCEDURE add_sub ;  
  4. --2.重新编译存储过程(当表结构发生变量,Oracle会将基于该表的存储过程转变成INVALID状态。为了避免过程运行出错,应该重新  
  5. --编译处理INVALID状态的过程。使用ALTER PROCEDURE 命令可以重新编译)  
  6.   
  7. ALTER PROCEDURE get_dept3 COMPILE ;  
  8.   
  9. --3确定过程状态  
  10. --为了确定处于INVALID状态的对象,可以查询数据字典USER_OBJECTS。例如,下述代码将查询处于INVALID状态的过程信息  
  11. SELECT * FROM user_objects   
  12. WHERE status= 'INVALID' AND object_type ='PROCEDURE';  
  13.   
  14. ---4查看过程文本  
  15.   
  16. SELECT text FROM user_source WHERE name =UPPER('get_dept3'AND type ='PROCEDURE';  

                                     7注意事项

oracle存储过程中is和as区别

在存储过程(PROCEDURE)和函数(FUNCTION)中没有区别;
在视图(VIEW)中只能用AS不能用IS;
在游标(CURSOR)中只能用IS不能用AS。

PLSQL

什么是PL/SQL程序

PL/SQL Procedure Language/SQL

PLSQLOraclesql语言的过程化扩展

PLSQL是面向过程的语言

[sql]  view plain  copy
  1. declare  (如果没有定义,可以不写)  
  2.     ---说明部分(变量、光标、或者例外)  
  3. begin   
  4.       
  5.    ---程序体(DML语句)  
  6. exception  
  7.    例外处理语句  
  8.    end ;  





1.基本数据类型 
PLSql 包括标量类型、复合类型、参照类型、LOB类型灯4种类型

1.1 标量变量
标量变量是指只能存放单个数值的变量。当定义标量变量时,需要指定标量数据类型,常用的标量数据类型有VARCHAR2,CHAR、NUMBER、DATE、BOOLEAN、LONG和BINARY INTEGER等。
1.声明变量
v_sno  VARCHAR2(20);
v_age NUMBER(2);
v_sex CHAR(1):='1' ;   //定义变量并且赋值
c_count CONSTANT NUMBER(2):=10 ; //定义常量
2.定义变量
v_sno:='95001';
v_age:=23;
另一种方式是使用SELECT INTO 语句或者FETCH INTO语句给变量赋值。
案例如下 
使用替换变量输入员工号,输出当前员工的相关信息
[sql]  view plain  copy
  1. DECLARE    
  2. v_ename VARCHAR2(10);    
  3. v_salary NUMBER(7,2);    
  4. v_hiredate DATE ;  
  5. today  DATE:=sysdate ;  
  6. nick  VARCHAR2(20);  
  7. BEGIN   
  8.   nick:='paul';    
  9.   SELECT ename ,sal,hiredate INTO v_ename,v_salary,v_hiredate    
  10.   FROM emp     
  11.   WHERE empno =&empno ;    
  12.   dbms_output.put_line('名字'|| v_ename);    
  13.   dbms_output.put_line('薪水'|| v_salary);    
  14.   dbms_output.put_line('入职日期'|| v_hiredate);  
  15.   dbms_output.put_line('昵称'||nick);  
  16.   dbms_output.put_line('今日时间:'||today);  
  17.   EXCEPTION     
  18.     WHEN NO_DATA_FOUND THEN     
  19.       dbms_output.put_line('您所输入的雇员不存在');    
  20.   END ;    


使用%TYPE
在定义变量时,如果其数据类型与已经定义的某个数据类型变量类型相同,或者与数据库表的某个列的数据类型相同,这时可以使用%TYPE,该属性会自动根据表列或其他变量的类型和长度定义新变量。
案例如下 
输入员工号,输出当前员工的相关信息
[sql]  view plain  copy
  1. DECLARE  
  2. v_ename emp.ename%TYPE ;  
  3. v_sal   emp.sal%TYPE ;  
  4. v_hiredate emp.hiredate%TYPE ;  
  5. BEGIN  
  6.   SELECT ename,sal,hiredate INTO v_ename,v_sal,v_hiredate FROM emp  
  7.   WHERE empno = &empno ;  
  8.   dbms_output.put_line('名字'|| v_ename);  
  9.   dbms_output.put_line('薪水'|| v_sal);  
  10.   dbms_output.put_line('入职日期'|| v_hiredate);  
  11.   EXCEPTION  
  12.     WHEN NO_DATA_FOUND THEN  
  13.       dbms_output.put_line('你所输入的雇员不存在');  
  14.   END ;  
记录类型
当使用PL/SQL记录时,既可以自定义记录类型和记录变量,也可以使用%ROWTYPE属性来定规记录变量。
案例1  输入员工号,输出当前员工的相关信息
自定义记录类型(切记切记)
[sql]  view plain  copy
  1. DECLARE   
  2. /** 首先记录类型 **/  
  3. TYPE emp_record_type IS RECORD (  
  4. ename emp.ename%TYPE ,  
  5. salary emp.sal%TYPE ,  
  6. hiredate emp.hiredate%TYPE   
  7. );   
  8.  /** 声明记录变量  **/  
  9. emp_record  emp_record_type ;  
  10. BEGIN  
  11.   SELECT ename,sal,hiredate INTO emp_record FROM emp   
  12.   WHERE empno=&empno ;  
  13.   dbms_output.put_line('名字'|| emp_record.ename);  
  14.   dbms_output.put_line('薪水'|| emp_record.salary);  
  15.   dbms_output.put_line('入职日期'|| emp_record.hiredate);  
  16.   EXCEPTION  
  17.     WHEN NO_DATA_FOUND THEN  
  18.       dbms_output.put_line('你所输入的雇员不存在');  
  19.   END ;  
  20.    
%ROWTYPE记录类型

[sql]  view plain  copy
  1. /** 使用%ROWTYPE记录类型**/  
  2. /**使用%TYPE类型可以使变量获得字段的数据类型,使用%ROWTYPE可以使变量获得整个记录的数据类型  
  3. %ROWTYPE属性用于基于表或视图定义记录变量。  
  4. 可以认为:使用%ROWTYPE 声明的变量封装了表或视图一行数据,当使用该属性定义记录变量时,记录成员的名称和  
  5. 类型与定义它所引用的表或视图的列的名称和类型一致。**/  
  6. DECLARE   
  7.  emp_record  emp%ROWTYPE ;  
  8.  BEGIN  
  9.    SELECT * INTO emp_record FROM emp WHERE   
  10.    empno=&empno ;  
  11.    dbms_output.put_line('名字:'|| emp_record.ename);  
  12.    dbms_output.put_line('薪水'|| emp_record.sal);  
  13.    dbms_output.put_line('入职日期'|| emp_record.hiredate);  
  14.    EXCEPTION  
  15.      WHEN NO_DATA_FOUND  THEN  
  16.        dbms_output.put_line('你所输入的雇员不存在');  
  17.          
  18.    END ;  

IF条件语法

[sql]  view plain  copy
  1. IF语句  
  2. 1   
  3. IF 条件   THEN 语句1 ;  
  4. 语句2 ;  
  5. END IF ;  
  6.   
  7. 2   
  8.   
  9. IF 条件 THEN  语句序列1;  
  10. ESLE  语句序列2;  
  11. END IF ;  
  12.   
  13. 3  
  14.   
  15. IF 条件 THEN  语句;  
  16. ELSIF 语句 THEN 语句;  
  17. ELSE  语句;  
  18. END IF ;  
例子
[sql]  view plain  copy
  1. DECLARE  
  2.  pnum  NUMBER:=#  
  3.  BEGIN  
  4.  IF pnum=0 THEN dbms_output.put_line('您输入的是:'||0);  
  5.  ELSIF pnum=1 THEN dbms_output.put_line('您输入的是:'||1);  
  6.  ELSIF pnum=2  THEN dbms_output.put_line('您输入的是:'||2);  
  7.  ELSE dbms_output.put_line('您输入的是啥');  
  8.  END IF ;  
  9.    END;  
CASE  WHEN  用法
--  case  when  用法  
declare 
grade char(10):=UPPER('&input');

begin 
case  grade
when  'A'  then  dbms_output.put_line('优秀');
when  'B'  then  dbms_output.put_line('一般');
end case ;
end ;
-- case  when  两种用法 
declare 
  v_number number :=&input ;

  begin 
  case  v_number 
    when 1  then  dbms_output.put_line('牛逼');  
  end case ;
   end ;
   
   
   
declare 
  v_number number:=&input  ;
  begin 
  case 
    when v_number>1  then  dbms_output.put_line('牛逼');  
    else dbms_output.put_line('太小啦');
  end case ;
   end ;
                                                                  字符串转换问题
--可转变的类型赋值
v_count :=TO_NUMBER('20');

v_pay:=TO_CHAR('3000.79');

--字符串转日期
v_date:=TO_DATE('2012.07.03','yyyy.mm.dd');

---日期转字符

v_now :=TO_CHAR(SYSDATE,'yyyy.mm.dd hh24:mi:ss');




循环用法

[sql]  view plain  copy
  1.   --打印1-10的值  
  2. 1.   
  3.   
  4.  while  条件  loop  
  5.   --执行内容  
  6.   end loop ;  
  7. declare  
  8. num  number :=1 ;   
  9. begin  
  10. while num<=10 loop  
  11. dbms_output.put_line(num);  
  12. --使num值+1  
  13. num:=num+1 ;  
  14. end loop ;  
  15. end;  
  16.   
  17. 2. Loop循环(推荐使用)  
  18. declare  
  19. pnum number:=1 ;  
  20. begin  
  21. loop  
  22. EXIT WHEN pnum>10 ;  
  23. dbms_output.put_line(pnum);  
  24. pnum:=pnum+1 ;  
  25. end loop ;  
  26. end;  
  27.   
  28.   
  29. For循环  
  30. declare  
  31. pnum number:=1 ;  
  32. begin  
  33. for pnum in 1..10 LOOP   
  34. dbms_output.put_line(pnum);  
  35. end loop;   
  36. end ;  
游标用法

光标(游标)

就是一个结果集(ResultSet)

光标的语法

CURSOR光标名 [(参数名数据类型[参数名数据类型])]  IS  SELECT语句 ;

[sql]  view plain  copy
  1. 如: CURSOR c1  is select ename from emp ;  
  2. --打开光标  
  3. open c1 ;   --(打开光标,执行查询)  
  4. --关闭光标  
  5. close c1 ;-- (关闭光标,释放资源)  
  6. --取一行光标的值;  
  7. fetch c1 into ename ;  
  8. --作用1把当前指针指向的记录返回 2将指针指向下一条记录  

(注意光标的属性有两种  %found 和 %notfound   返回值都是truefalse)

例子:
查询所有员工的名字和工资
[sql]  view plain  copy
  1. declare  
  2. --声明光标  
  3. cursor results is select ename ,sal from emp ;  
  4. rname emp.ename%TYPE ;  
  5. rsal  emp.sal%TYPE ;  
  6. begin  
  7. --打开光标  
  8. open results ;  
  9. loop  
  10. exit when results%notfound ;  
  11. fetch results into rname,rsal ;  
  12. dbms_output.put_line(rname||'的薪水是'||rsal);  
  13. end loop ;  
  14. --关闭游标  
  15. close results ;  
  16. end ;  

例子  给员工涨工资 
[sql]  view plain  copy
  1. ---按照员工的职位涨工资,总裁CLERK涨1000 经理MANAGER涨800  其他人400  
  2. declare  
  3. --声明光标  
  4. cursor results is select empno ,job from emp ;  
  5. reno emp.empno%TYPE ;  
  6. rjob  emp.job%TYPE ;  
  7. begin  
  8. --打开光标  
  9. open results ;  
  10. loop  
  11. exit when results%notfound ;  
  12. fetch results into reno,rjob ;  
  13. if rjob='PRESIDENT' then update emp set  sal=sal+1000 where empno= reno ;  
  14. elsif rjob='MANAGER' then update emp set sal=sal+800 where empno= reno ;  
  15. else update emp  set  sal=sal+400 where empno= reno ;  
  16. end if ;  
  17. end loop ;  
  18. --关闭游标  
  19. close results ;  
  20. commit ;  
  21. end ;  
光标的另外两个属性 
光标 %isopen   判断光标是否打开
光标%rowcount 被影响的条数


光标数的限制:默认情况下oracle数据库只允许在同一会话中,打开300个光标。

案例 带参数的光标
-- 查询某个部门下的名字和薪水  
declare  
cursor res(dno number) is select ename ,sal from emp  where deptno =dno ;  
myname emp.ename%TYPE;  
mysal  emp.sal%TYPE;  
begin  
  open res(10);  
  loop   
   fetch res into myname,mysal ;  
  dbms_output.put_line(myname||'的薪水是'||mysal);    
  exit when res%notfound ;  
    
  end loop ;  
    
  close res ;  
end ; 
PLSQL中的例外
系统例外
no_data_found  没有找到数据


too_many_rows  (select ...into 语句匹配多个行)


zero_divide (被0除)


value_error (算数或转换错误)


timeout_on_resource (在等待资源时发生超时)


自定义例外
案例如下
-- no_data_found异常
declare 
dname emp.ename%TYPE;
begin
select ename into dname from emp where empno=&inputno ;

dbms_output.put_line('这个人是:'||dname);
exception
when no_data_found then
dbms_output.put_line('没有找到这个人');
when  others then
dbms_output.put_line('其他异常');
end ;
--too_many_rows异常

declare
dname emp.ename%TYPE;
begin

select ename  into dname from emp where deptno=20 ;
dbms_output.put_line(dname);
exception
when too_many_rows  then
dbms_output.put_line('查询到多行数据');
when others then
dbms_output.put_line('其他异常');
end;

--zero_divide   除数为0



declare
num number ;
begin 
num:=2/0 ;

exception
when zero_divide  then
dbms_output.put_line('0不能做除数');
when others then dbms_output.put_line('其他异常');

end ;



---value_error  转换异常


declare
num  number;

begin
num:='abc';
dbms_output.put_line(num);
exception 
when value_error  then
dbms_output.put_line('转换异常');
when  others then
dbms_output.put_line('其他异常');
end ;

自定义异常  查询部门为50的员工名字
--需求:查询50号部门的员工名字
declare
dname emp.ename%TYPE ;
no_data  exception ;
cursor res is select ename  from emp  where  deptno=50;
begin
  open res ;
  loop
   fetch  res into dname ;

   exit when res%notfound ; 
  end loop ;
  if res%notfound  then
    raise no_data ;
   end if ;

  exception 
  when  no_data  then 
    dbms_output.put_line('无查询数据');   
  close res ;
end ;
案例
---统计每年入职的员工人数
declare
cursor res is select to_char(hiredate,'yyyy') ,count(*) from emp group by to_char(hiredate,'yyyy');
hiredateyear  varchar2(20);
cishu number(20);
alls  number(20):=0;
begin
open res ;
loop
fetch  res into hiredateyear ,cishu ;
exit when res%notfound;
dbms_output.put_line('入职日期:'||hiredateyear||'次数'||cishu);
alls:=alls+cishu;
end loop ;
dbms_output.put_line('总次数='||alls);
close res ;
end ;
---为员工涨工资。从最低工资涨起每人涨10%,但工资总额不能超过5万元,请计算涨工资的人数和
---涨工资后的工资总额,并输出。
declare
cursor res is  select empno, sal from emp order by sal;
allmoney number:=0 ;
currallmoney number ;
eno emp.empno%TYPE  ;
esal emp.sal%TYPE   ;
times number:= 0    ;
 begin
  open res ;
  loop 
  fetch res into eno,esal ;
  update emp  set sal=sal+sal*0.1 where  empno =eno ;
  times:=times+1 ;
   exit when  currallmoney>50000 ;
   exit when res%notfound;
  select sum(sal) into currallmoney from emp ;
   end loop ;
   dbms_output.put_line('钱:'||currallmoney);
   dbms_output.put_line('次数:'||times);
  close res ;
 end ;
 
---分别统计 <3000   3000-6000  >6000各个部门的人数  和总金额
  declare
 ccount_3000  number ;
 ccount_6000 number ;
 ccount_7000 number ;
 total_10_sal emp.sal%TYPE;
 pno  number;
 cursor res is select distinct(deptno) from emp ;
 begin
  open res ;
   loop
  fetch res  into pno ;
  exit when res%notfound ;
  select  nvl(sum(count(*)),0)    into ccount_3000  from emp  e  inner join  dept d   on e.deptno=d.deptno  where d.deptno =pno and e.sal<3000 group by d.deptno;
  select  nvl(sum(count(*)),0)    into ccount_6000  from emp  e  inner join  dept d   on e.deptno=d.deptno  where d.deptno =pno and e.sal>3000 and e.sal<6000 group by d.deptno;
  select  nvl(sum(count(*)),0)   into ccount_7000  from emp  e  inner join  dept d   on e.deptno=d.deptno  where d.deptno =pno and e.sal>6000  group by d.deptno  ;
  select sum(e.sal) into  total_10_sal from emp  e  inner join  dept d   on e.deptno=d.deptno  where d.deptno =pno  group by d.deptno  ;

  insert into msg values (pno,ccount_3000,ccount_6000,ccount_7000,total_10_sal);
 end loop ;
 close res ;
 end ;
---按系别分段统计 成绩 60   60--85    85以上  大学物理的各分段 学生成绩人数
declare 
countnum60 number ;
countnum68 number ;
countnumhigh80 number ;
xiname dep.dname%TYPE;
lession  course.cname%TYPE:='大学物理';
avgauto  number ;
cursor res is   select distinct(dname) from dep;
begin
open res ;
loop 
fetch res into xiname ;
select nvl(sum(count(*)),0)  into countnum60 from student s  inner join dep d on s.dno=d.dno  inner join sc on sc.sno=s.sno 
inner join course c on c.cno=sc.cno  where c.cname='大学物理' and sc.grade<=60 and d.dname=xiname  group  by d.dname ;

select nvl(sum(count(*)),0) into countnum68 from student s  inner join dep d on s.dno=d.dno  inner join sc on sc.sno=s.sno 
inner join course c on c.cno=sc.cno  where c.cname='大学物理' and sc.grade>60 and sc.grade<85 and d.dname=xiname   group  by d.dname ;

select nvl(sum(count(*)),0) into countnumhigh80 from student s  inner join dep d on s.dno=d.dno  inner join sc on sc.sno=s.sno 
inner join course c on c.cno=sc.cno  where c.cname='大学物理' and sc.grade>85 and d.dname=xiname   group  by d.dname ;

select avg(sc.grade) into avgauto from student s  inner join dep d on s.dno=d.dno  inner join sc on sc.sno=s.sno 
inner join course c on c.cno=sc.cno  where c.cname='大学物理' and d.dname=xiname   ;
exit when res%notfound ;
insert into msg2 values(lession,xiname,countnum60,countnum68,countnumhigh80,avgauto);
end loop ;
close res ;
end ;






  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值