Oracle深入学习

6 篇文章 0 订阅

一、异常

异常是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性。
1、Oracle预定义异常
命名的系统异常                          产生原因
ACCESS_INTO_NULL             未定义对象
CASE_NOT_FOUND  CASE         中若未包含相应的 WHEN ,并且没有设置 ELSE 时
COLLECTION_IS_NULL           集合元素未初始化
CURSER_ALREADY_OPEN          游标已经打开
DUP_VAL_ON_INDEX             唯一索引对应的列上有重复的值
INVALID_CURSOR               在不合法的游标上进行操作
INVALID_NUMBER               内嵌的 SQL 语句不能将字符转换为数字
NO_DATA_FOUND                使用 select into 未返回行,或应用索引表未初始化的元素时
TOO_MANY_ROWS                执行 select into 时,结果集超过一行
ZERO_DIVIDE                  除数为 0
SUBSCRIPT_BEYOND_COUNT       元素下标超过嵌套表或 VARRAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT      使用嵌套表或 VARRAY 时,将下标指定为负数
VALUE_ERROR                  赋值时,变量长度不足以容纳实际数据
LOGIN_DENIED                 PL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码
NOT_LOGGED_ON                PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据
PROGRAM_ERROR                PL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包
ROWTYPE_MISMATCH             宿主游标变量与 PL/SQL 游标变量的返回类型不兼容
SELF_IS_NULL                 使用对象类型时,在 null 对象上调用对象方法
STORAGE_ERROR                运行 PL/SQL 时,超出内存空间
SYS_INVALID_ID               无效的 ROWID 字符串
TIMEOUT_ON_RESOURCE Oracle   在等待资源时超时
2、异常演示
--NO_DATA_FOUND  异常
declare  
   v_name t_student.name%type;   --学生姓名
   v_edu t_student.edu%type;   --学历
   v_msg varchar2(100);
begin
   select name,edu into v_name,v_edu  from t_student where id=100;  
   v_msg:=v_name||v_edu;
   dbms_output.put_line(v_msg);  
exception  --捕捉异常
  --判断是否是我们需要的异常
  when no_data_found then
    --处理异常
    dbms_output.put_line('没有找到数据');  
    --when others 可以用于捕获其他的异常
when others then
     dbms_output.put_line('其他异常');  

    --处理异常
end;
3、自定义异常
--自定义异常方式  声明变量时,类型为exception
--抛出异常  raise 异常名称。
在插入学员数据时,如果性别为其他数据时显示异常输出“请正确输入性别值”
declare
  v_row t_student%rowtype;
  --声明自定义异常
  exc_sex exception;
begin
  select seq_student.nextval into v_row.id from dual;
  v_row.name:='李大明白';
  v_row.sex:=1;
  v_row.edu:='本科';
  v_row.tele:=null;
  v_row.cardno:=null;
  v_row.classid:=1;
  if v_row.sex not in (0,1) then
    --抛出异常 
    raise exc_sex;
  end if;  
  insert into t_student values(seq_student.nextval,v_row.name,
  v_row.sex,v_row.edu, v_row.tele,v_row.cardno,v_row.classid);
  commit;
exception
--捕捉异常
  when exc_sex then
    dbms_output.put_line('请正确输入性别值');
end;
4、自定义异常绑定错误编号
因为Oracle中的异常只有21中,很多异常没有预置,需要通过自定义异常绑定错误编号的方式进行解决。
declare
error_check exception;--自定义异常
pragma exception_init(error_check,错误编号) --自定义异常绑定错误编号 
--一个自定义异常只能绑定一个错误编号。
--处理绑定错误编号的自定义异常和普通的自定义异常的方式相同。

二、触发器

1、触发器介绍

   触发器是数据库对象之一,该对象与编程语言中的函数比较类似,都需要声明和执行等。
但是触发器不需要由程序调用,也不需要手动启动,而是由事件来触发、激活从而实现执行。
   Oracle数据库中数据库触发器是一个与表相关联的、存储的PL/SQL程序。每当一个特定的
数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle自动地执行触发器中定义的语句序列。 
例如:学生表中有学生信息、学生总数等记录,当添加一条学生记录时,需要及时更新学生总数。
这时就可以创建一个触发器对象,每次添加一条学生记录时,就执行一次计算学生总数的操作。
触发器一般在执行delete语句、insert语句、update语句时触发,执行其他SQL语句时则不会激活 。
    触发器可以用于数据确认、实施复杂的安全性检查、做审计、跟踪表上所做的数据操作等、数据的备份和同步。

2、创建触发器

格式:
CREATE  [or REPLACE] TRIGGER  触发器名
 BEFORE | AFTER
  [DELETE ][[or] INSERT] [[or]UPDATE [OF 列名]]
 ON  表名
--for each row 的意思是行级触发器  行级触发器每修改一行,执行一次
--不写,默认为语句级触发器,语句级触发器的作用是,无论修改多少行,只执行一次。
  [FOR EACH ROW [WHEN(条件) ] ]
declare
   ……
begin
       PLSQL 块 
End ;

解释:
    trigger 表示触发器的意思
    触发器名称建议trigger_xxx
    before|after表示触发器执行时间,before表示触发器在事件执行之前执行,
        after表示触发器在事件执行之后执行。
    dlelet|insert|update表示激活触发器的事件
    表名是指触发器操作的表的名称。
    for each row 表示任何一条记录上的操作都会激活触发器。
    PLSQL块,表示触发器激活之后,执行的SQL语句。

    在触发器中触发语句与伪记录变量的值
    触发语句        :old                      :new
    Insert     所有字段都是空(null)       将要插入的数据
    Update     更新以前该行的值            更新后的值
    delete     删除以前该行的值            所有字段都是空(null)

3、使用触发器

--before触发器
--案例需求:班级,插入班级信息时,自动指定班级id

--创建触发器
create trigger tri_class 
before insert on t_class for each row

begin
       select seq_class.nextval into :new.id from dual;

end;

--执行插入记录,测试触发器是激活
insert into t_class(name,type,state,opendate) values('实验班31班',2,1,to_date('2016-06-10','yyyy-mm-dd'));
select * from t_class order by id;

--after触发器
--修改学员的学历时自动记录修改前和修改后的学历
--建表
create table t_edu_log(
id number primary key,
update_date date,
studentid number,
edu0 varchar2(30),--修改之前的学历
edu1 varchar2(30) –修改后的学历
);
--创建序列
create sequence seq_log;

创建触发器
create or replace trigger tri_student_edu_update
 after
update of edu
 on t_student
for each row
declare

begin
  --:old   :new
  insert into t_edu_log values (seq_log.nextval,sysdate,
  :old.id,:old.edu,:new.edu
  );
end;

三、游标

1、游标简介

在写java程序中有结果集的概念,那么在pl/sql中也会用到多条记录,
这时候我们就要用到游标,游标可以存储查询返回的多条数据。
游标可以理解为是PL/SQL中的结果集,我们通过游标可以提取结果集中的每行记录。
游标可以看作一种数据类型,可以用来遍历结果集,相当于指针,或者数组中的下标。
处理结果集的方法可以通过游标定位到结果集的某一行,从当前结果集的位置搜索一行或一部分
行或者对结果集中的当前行进行数据修改。
for 循环遍历游标的时候,变量默认声明为rowtype类型

2、使用游标

2.1声明游标
声明游标要写到declare下,类似于声明变量
语法格式(Oracle数据库)
declare
cursor cursor_name is SQL语句;
2.2打开游标
open cursor_name;   
2.3使用游标
open 游标名称
loop
    --使用的变量一般是记录型引用
    --遍历游标使用fetch into 关键字
   fetch 游标名称 into 变量  
    --判断游标是否结束  游标名称%notfound
   exit  when  游标名称%notfound
end loop;
close 游标名称
2.4关闭游标
close cursor_name;
2.5游标使用案例
--例如 需求 控制台输出女学员信息 

 --声明游标
 select * from t_student where sex='0'; 
declare
  cursor cursor_girl is select * from t_student where sex='0'; 
  v_student t_student%rowtype;
begin
      --开启游标
  open cursor_girl;
  loop
    fetch cursor_girl into v_student;
    exit when cursor_girl%notfound;
    --如果输出语句放在exit上面,最后一条记录会输出两遍,因为当第一次输出最后一条记录后,
    --判断notfound为true,之后,输出语句会再次执行一次,所以总共执行两次
    dbms_output.put_line(v_student.ID||'  '|| v_student.NAME||'  '||v_student.SEX);
  end loop;
  --关闭游标
  close cursor_girl;
end;
2.6有参数的游标
--当声明游标时如果参数暂时不能指定,可使用有参数的游标
--声明游标时,游标名称(参数)   where 字段=参数
--开启游标时,传入参数    open cursor_name(实际参数);
declare
  cursor cur_student(v_sex number) is select * from t_student where sex=v_sex;--声明游标
  r_student t_student%rowtype;--学员表行类型
begin

  open cur_student(1);--打开游标
  loop
    fetch  cur_student into  r_student ;
    exit when cur_student%notfound;--退出循环
    dbms_output.put_line( '学员姓名:'||r_student.name || '  身份证号'||r_student.cardno );
  end  loop;
  close cur_student;--关闭游标
end ;

--使用for循环遍历游标,更加简单,简化了开启游标,遍历游标的过程
declare
  cursor cur_student(v_sex number) is select * from t_student where sex=v_sex;--声明游标
  begin
  for r_student in cur_student(1)
  loop    
dbms_output.put_line( '学员姓名:'||r_student.name || '  身份证号'||r_student.cardno );
  end  loop;  
end ;
2.7 系统引用游标
--声明游标时,类型为sys_refcursor
--初始化游标使用 open 游标名  for 'SQL语句'
--之后游标的使用和普通游标的使用是一样的
  declare
--声明系统引用游标 
cur_girl sys_refcursor;
v_student t_student%rowtype;
begin 
  --初始化系统引用游标
  open  cur_girl for select * from t_student where sex='0' ;

  loop
    fetch cur_girl into v_student;
   -- dbms_output.put_line(v_student.ID||'  '|| v_student.NAME||'  '||v_student.SEX);
      exit when cur_girl%notfound;
      -
    dbms_output.put_line(v_student.ID||'  '|| v_student.NAME||'  '||v_student.SEX);
  end loop;
  --关闭游标
  close cur_girl;
end;
2.8 隐式游标
--不需要声明,就直接使用的游标,相当于系统直接提供的游标,游标名称固定为SQL
--作用:通过隐式游标的属性,可以获取刚才执行语句的结果
--属性 %found:之前执行的SQL语句有结果
     %notfounde 之前执行的SQL语句没结果
 declare
 v_name varchar2(111);
 begin 
  select name into v_name from t_student where id=2; 
 if  SQL%notfound then
        dbms_output.put_line('1');
   else
        dbms_output.put_line('21'); 
        commit;
   end if;     

end;

四、存储过程

1、存储过程简介
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,
经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它.
在编程语言中连接Oracle数据库,使用存储过程的效率比直接使用SQL语句效率要高,
因为SQL语句需要进行编译,再进行解释执行。
而存储过程在创建时就已经编译了,之后直接解释执行即可,所以性能较高。
存储过程实际就是被命名的PL/SQL语句
2、创建存储过程
CREATE [ OR REPLACE ]  PROCEDURE   存储过程名称
 (参数,参数,参数)
IS|AS
  变量声明部分;
BEGIN
  逻辑部分
[EXCEPTION 
  异常处理部分]
END;

--举例   创建一个添加学生信息的存储过程
create procedure pro_student_add (
v_name varchar2,
v_sex number,
v_edu varchar2,
v_tele varchar2,
v_sex varchar2,
v_cardno varchar2,
v_classid number
)
as 
begin 
    insert into t_student(id,name,sex,edu,tele,cardno,classid) 
    values(seq_student.nextval,v_name,v_sex,v_edu,v_tele,v_cardno,v_classid);
    --因为执行的是插入操作,所以需要提交事务
    commit;
end;
3、调用存储过程
--使用begin end 调用
begin
--存储过程名称(参数)
pro_student_add('买买提2',1,'本科','2345667','123456789012345678',2);  
end;
--使用call调用 call 存储过程名称(参数)
call pro_student_add('买买提2',1,'本科','2345667','123456789012345678',2);
--在JDBC中调用  
--语句执行者使用CallableStatement 
CallableStatement callStatement = conn.prepreCall("call pro_student_add(?,?,?,?,?,?)");
--传入参数的方式和预处理的方式相同

--创建带返回参数的存储过程
create or replace procedure proce_student_add
(
v_name varchar2,
v_sex number,
v_edu varchar2,
v_tele varchar2,
v_cardno varchar2,
v_classid number,
***--out表示该参数可以返回***
v_id out number
)
as
begin
  insert into t_student(id,name,sex,edu,tele,cardno,classid)
  values(seq_student.nextval,v_name,v_sex,v_edu,v_tele,v_cardno,v_classid);  
  --因为是插入,所以需要进行提交事务
  commit;
  --获取返回的参数
  select seq_student.currval into v_id from dual;
end;
declare 
v_id number;
begin 
 proce_student_add('买买提2',1,'本科','2345667','123456789012435678',2,v_id);
 dbms_output.put_line('当前学生编号:'||v_id);
 end;

--JDBC获取存储过程返回参数
![](http://i.imgur.com/cFrPNzS.png)

五、存储函数

1、存储函数概述
存储函数就是我们自定义的函数,调用方法与ORACLE内置的函数相同。创建语法与存储过程类似。
存储函数与存储过程的不同之处在于:
1.存储过程是通过传出参数的方式返回结果,可以有多个返回值。而存储函数只有一个返回值。
2.存储过程通常是被应用程序所调用,而存储函数通常是在SQL语句中被调用。
2、创建存储函数
CREATE [ OR REPLACE ]  FUNCTION 存储函数名称
 (参数,参数,参数)
RETURN 数据类型
IS
  变量声明部分;
BEGIN
  逻辑部分
  return 返回值
END;
--创建存储函数举例

--创建一个函数,通过传入学生id,就可以返回学生name
 create or replace function fun_getnamebyid(v_id number)
 return varchar2
 is
 v_name varchar2(30);
 begin
 select name into v_name from t_student where id=v_id;
 return v_name;   
--需要处理异常
 exception
   when no_data_found then
     return '--';
 end;
3、调用存储函数
调用函数的方法比较简单,和调用Oracle内置函数的方法一致,函数名(参数)即可
 begin
    dbms_output.put_line(fun_getnamebyid(3));  
 end;

触发器、存储函数、存储过程

1、区别
触发器的执行不是由程序调用,也不是由手动启动,而是由事件来触发、激活从而实现执行。
存储过程和存储函数需要手动调用存储过程或者存储函数的名字来执行。
存储函数必须要有返回值,而且只能有一个返回值。主要是在SQL语句中调用。
存储过程可以没有返回值,如果有可以有一到多个返回值。存储过程主要是为了编程语言调用。
2、存储过程和存储函数的优点
存储过程和函数由于标准组件式编程,提高了SQL语句的重用性、共享性和可移植性。
存储过程和函数能够四线较快的执行速度,减少网络流量。
存储过程和函数可以被作为一种安全机制来利用。
3、存储过程和函数的缺点
存储过程和函数的编写比单据sql语句复杂,需要用户具有更高的技能和更丰富的经验。
在编写存储过程和函数时,需要创建这些数据库对象的权限。
简单来说存储过程和函数编写复杂,但使用起来相对比较简单。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值