• oracle学习总结2(pl/sql 游标 异常的处理 存储过程和函数 包 触发器)


    pl/sql的学习

    给sql添加了逻辑判断与流程控制的功能

    语法:

    declare

    begin

    exception

    end;

    运算符  

      重要的就是赋值运算符了:=        连接  ||      ** 平方

     常用的数据类型

    也就是oracle常用的数据类型

    constanct常量的声明

    引用  constanct nubmer:=1;

    pl/sql操作数据

    1.不能直接查出来,缺少into子句

       需要将查询的数据放到变量当中

    2.每次查询只能查询一条数据赋值给变量

       实际返回的行数超出请求的行数

    复合数据类型

    %type

    %rowtype

    varray

    type 类型名  is varray(maxnum_size) of  数据类型

    创建数组对象的引用 然后赋值 

    v_str  strings:=strings('aa','bb')

    table(相当于可变数组)

    type 类型名  is table  of 数据类型    index  by binary_integer (数组角标无下限)

    创建可变数组对象的引用,然后赋值

    record(相当于java中的集合)

    type 类型名 is record  (定义不同的类型);

    创建集合对象的引用

    --pl/sql操作数据
    --复合数据类型
    --varray
    declare
    type strings is varray(5) of varchar2(10);--定义一个数组数组元素的长度为5个,每个是10个可变长度
    v_str strings:=strings('aa','bb','cc','dd','ee');--创建一个数组对象的引用   从一开始的
    begin
      dbms_output.put_line(v_str(1));
      dbms_output.put_line(v_str(2));
      dbms_output.put_line(v_str(3));
      dbms_output.put_line(v_str(4));
      dbms_output.put_line(v_str(5));
      end;
    --table  可以理解为java中的可变数组
    declare
    type strings is table of varchar2(10) index by binary_integer;--定义一个可变数组,数组中每个元素的可变长度为10
    --数组角标没有下限
    v_str strings;--定义一个可变数组对象的应用
    begin
      v_str(1):='aa';
      v_str(999):='bb';
      dbms_output.put_line(v_str(1)||v_str(999));
      end;
    --record
    declare
    --可以定义多个类型
    type strings is record(
        v_name tb_student.lastname%type,
        id number,
        r_tb_student tb_student%rowtype
    );
    v_str strings;
    begin
      select id,lastname,sex,age,email,address into v_str.r_tb_student.id,v_str.v_name,v_str.r_tb_student.sex
      ,v_str.r_tb_student.age,v_str.r_tb_student.email,v_str.r_tb_student.address from tb_student where id=2;
      dbms_output.put_line(v_str.v_name);
      end;
    

    流程控制

    if

    loop循环

    for循环

    for  变量名   in  1 ..5 loop

    end loop;

    while循环

    while (布尔表达式) loop

    end loop;

    --流程控制
    --分支语句
    declare
      v_str varchar2(10):='b';
    begin
      if(v_str='a') then
      dbms_output.put_line('if');
      elsif(v_str='b') then
      dbms_output.put_line('elsif');
      else
        dbms_output.put_line('else');
        end if;
      end;
      
    declare 
       i constant number:=4;
    begin
      if(i=5) then
      null; --如果什么都不做的话,那么补null来保证语句的完整性
      elsif(i=4) then
         dbms_output.put_line(i);
      else
        dbms_output.put_line('else');
        end if;
      end;
    
    --验证如果不给字符变量赋值时默认是空字符串还是为空
    declare
      i varchar2(10);
    begin
      if(i='') then
      dbms_output.put_line('空字符串');
      elsif(i is null) then
        dbms_output.put_line('null');
      elsif(i='a') then
      dbms_output.put_line('a');
      else
          dbms_output.put_line('b');
        end if;
      end;
      
    declare
      i number;
    begin
      if(i='') then
      dbms_output.put_line('空字符串');
      elsif(i is null) then
        dbms_output.put_line('null');
      elsif(i='a') then
      dbms_output.put_line('a');
      else
          dbms_output.put_line('b');
        end if;
      end;
      
      
    --循环控制
    --简单循环loop
    declare 
       i number:=0;
    begin 
      loop
        i:=i+1;
        dbms_output.put_line('i='||i);
        if(i=30) then
        exit;
        end if;
        end loop;
      end;
    declare 
       i number:=0;
    begin 
      loop
        i:=i+1;
        dbms_output.put_line('i='||i);
        exit when (i=30); 
        end loop;
      end;
      
    --嵌套循环
    declare
       i number:=0;
       b number:=0;
    begin
       loop
         i:=i+1;
         dbms_output.put_line('i>>>>>>='||i);
         exit when i=5;
         b:=0;
         --嵌套循环
         loop 
           b:=b+1;
           dbms_output.put_line('b='||b);
           exit when b=2;
           end loop;
         end loop;
      end;
    declare
       i number:=0;
       b number:=0;
    begin
       loop
         i:=i+1;
         dbms_output.put_line('i>>>>>>='||i);
         exit when i=5;
         b:=0;
         --嵌套循环
         loop 
           
           dbms_output.put_line('b='||b);
           exit when b=2;
           b:=b+1;
           end loop;
         end loop;
      end;
    declare
       i number:=0;
       b number:=0;
    begin
       <<outer>>loop
         i:=i+1;
         dbms_output.put_line('i>>>>>>='||i);
         exit when i=5;
         b:=0;
         --嵌套循环
         <<inner>>loop 
           
           dbms_output.put_line('b='||b);
           exit outer when b=2;
           b:=b+1;
           end loop;
         end loop;
      end;
    --for循环
    declare 
      a constant number:=4;
      b constant number:=10;
    begin 
      for i in a ..b loop
        dbms_output.put_line('i'||i);
        end loop;
      end;
    declare 
      a constant number:=1;
      b constant number:=10;
    begin 
      for i in a ..b loop
        dbms_output.put_line('i'||i);
        end loop;
      end;
    declare 
      a constant number:=1;
      b constant number:=10;
    begin 
      for i in reverse a ..b loop
        dbms_output.put_line('i+>>>>>'||i);
        end loop;
      end;
    --while循环
    declare 
      a constant number:=1;
      b constant number:=10;
      i number:=0;
    begin 
      while (b>a) loop
        i:=i+1;
        dbms_output.put_line('i='||i);
        exit when i=5;
        end loop;
      end;
    

    异常处理

    异常没有父子继承关系

    oracle可根据异常名设置多个异常处理代码    在异常块一次运行过程中,只有一个异常处理器会处理异常

    语法:

    when   异常名  then

    最后一句 条件when other  then

    两个常用的异常相关函数

    sqlcode返回错误代码        sqlerrm 返回错误代码关联的消息

    通过建立错误表来存储错误信息

    游标

    什么是游标

    游标为内存地址的引用,那段内存存放了多条sql语句执行的结果

    oracle数据库中执行的每个sql语句都有对应的独立的游标

    游标提供了访问select 语句执行结果的途径

       隐式游标

           由开发人员声明和控制    定义一个游标,将tb_clazz中所有的信息提取出来

      显示 游标

    cursor  游标名  is   sql语句

       游标流程一般是这样的

    定义游标 ——>打开游标——>提取数据 ——>关闭游标

    用fetch......into提取数据

     fetch  游标  into 存储的变量的引用

    带参数的游标  

    cursor   游标名(参数  参数类型)

    --异常处理
    declare
    r_tb_clazz tb_clazz%rowtype;
    begin 
      select * into r_tb_clazz from tb_clazz where id=2;
      dbms_output.put_line(r_tb_clazz.code);
      exception
      when no_data_found then
        dbms_output.put_line('没有数据');
        when others then
          dbms_output.put_line('others');
    end;
    --两个异常函数
    --sqlcode   返回错误代码
    --sqlerrm    返回错误代码关联的消息
    create table tb_error(
    id number primary key,
    tablename varchar2(20),
    sqlcode varchar2(50),
    sqlerrm varchar2(200),
    currdate date default sysdate
    )
    
    create sequence tb_error_seq;
    declare
    r_tb_clazz tb_clazz%rowtype;
    v_sqlcode varchar2(50);
    v_sqlerrm varchar2(200);
    begin 
      select * into r_tb_clazz from tb_clazz where id=2;
      dbms_output.put_line(r_tb_clazz.code);
      exception
      when no_date_found then
        dbms_output.put_line('没有数据');
        when others then
          dbms_output.put_line('others');--一定要以这个为结束;
    end; 
    
    
       
    declare
    r_tb_clazz tb_clazz%rowtype;
    v_sqlcode varchar2(50);
    v_sqlerrm varchar2(200);
    begin 
      select * into r_tb_clazz from tb_clazz where id=2;
      dbms_output.put_line(r_tb_clazz.code);
      exception
      when others then
        v_sqlcode:=sqlcode;
        v_sqlerrm:=sqlerrm;
        insert into tb_error (id,tablename,sqlcode,sqlerrm) values(tb_error_seq.nextval,'a',v_sqlcode,v_sqlerrm);
        commit;
    end;  
    insert into tb_clazz (id,code) values(2,'aaa');
        commit;
    declare
    r_tb_clazz tb_clazz%rowtype;
    v_sqlcode varchar2(50);
    v_sqlerrm varchar2(200);
    begin 
      select * into r_tb_clazz from tb_clazz;
      dbms_output.put_line(r_tb_clazz.code);
      exception
      when others then
        v_sqlcode:=sqlcode;
        v_sqlerrm:=sqlerrm;
        insert into tb_error (id,tablename,sqlcode,sqlerrm) values(tb_error_seq.nextval,'a',v_sqlcode,v_sqlerrm);
        commit;
    end;      
    select * from tb_error;
    
    
    --游标
    --提取tb_clazz表所有的数据
    declare
    --创建一个游标
       cursor c_tb_clazz is
       select * from tb_clazz;
       v_tb_clazz tb_clazz%rowtype;
    begin
      --打开游标
      open c_tb_clazz;
      --提取数据
      fetch c_tb_clazz into v_tb_clazz;
      dbms_output.put_line('id='||v_tb_clazz.id);
      fetch c_tb_clazz into v_tb_clazz;
      dbms_output.put_line('id='||v_tb_clazz.id);
      --关闭游标
      close c_tb_clazz;
      end;
    --循环提取
    declare
    --创建一个游标
       cursor c_tb_clazz is
       select * from tb_clazz;
       v_tb_clazz tb_clazz%rowtype;
    begin
      --打开游标
      open c_tb_clazz;
      --提取数据
      loop
      fetch c_tb_clazz into v_tb_clazz;
      exit when c_tb_clazz%notfound;
      dbms_output.put_line('id='||v_tb_clazz.id);
      dbms_output.put_line('code='||v_tb_clazz.code);
    
      end loop;
      --关闭游标
      close c_tb_clazz;
    end;
    
    --提取每个班级的信息,包括班级里面学生信息
    declare
     cursor c_tb_clazz is
     select * from tb_clazz;
     cursor c_tb_student(v_class_id number) is
     select * from tb_student where class_id=v_class_id;
     r_tb_clazz tb_clazz%rowtype;
     r_tb_student tb_student%rowtype;
    begin
      --打开游标
      open c_tb_clazz;
      --提取数据
      loop
        fetch c_tb_clazz into r_tb_clazz;
        exit when c_tb_clazz%notfound;
         dbms_output.put_line('第'||r_tb_clazz.id||'班');
        dbms_output.put_line('班级名为--'||r_tb_clazz.code);
        --********************************
        open c_tb_student(r_tb_clazz.id);
        loop
          fetch c_tb_student into r_tb_student;
          exit when c_tb_student%notfound;
          dbms_output.put_line('姓名:'||r_tb_student.lastname);
          end loop;
          close c_tb_student;
        end loop;
       
      --关闭游标
      close c_tb_clazz;
      end;
    select * from tb_clazz;
    truncate table tb_clazz;
    truncate table tb_student;
    delete from tb_student;
    delete from tb_clazz;
    create sequence tb_clazz_seq;
    begin
    insert into tb_clazz(id,code) values(tb_clazz_seq.nextval,'fpp');
    insert into tb_clazz(id,code) values(tb_clazz_seq.nextval,'许洁');
    commit;
    end;
    drop sequence tb_student_seq;
    create sequence tb_student_seq;
    select * from tb_course;
    begin
      insert into tb_student(id,lastname,age,sex,email,address,class_id,course_id,great)
      values(tb_student_seq.nextval,'付鹏鹏',21,'男','123@qq.com','南昌',1,2,98);
      insert into tb_student(id,lastname,age,sex,email,address,class_id,course_id,great)
      values(tb_student_seq.nextval,'许洁',20,'女','231@qq.com','邯郸',2,2,98);
      commit;
      end;
    

     存储过程和函数

    pl/sql程序单元    作为数据库对象保存在数据库里

    主要有4类

        1.存储过程    没有返回结果  执行特定的操作

        2.函数    有返回值    进行复杂计算

       3.包     相当于java中的类     逻辑上相关的过程和函数组织在一起

       4.触发器     事件触发,执行相应的操作

    参数模式

      in                                out                                        inout

    传递给子程序                 可以改变                              可以改也可以不改

    子程序不能改变参数值

    create   or  replace procedure  存储过程名

    is

    begin

    end;

    如果f8的话没有执行,而是编译,只有调用了他才会执行

    函数

    函数只有in  没有out 和inout

    create  or replace function 函数名(参数  参数类型) return   返回值类型

    is

    begin

    end;

    包(相当于java中的接口  他还有一个包体相当于实现类     只要在包中定义了的,在包体中都要实现)

    create or replace package 包名  

    is

    begin

    end

    包体

    create or replace package body 包名(要和包名一致否则会出错)

    is

    begin 

    end;

    --存储过程(没有返回值的函数)和函数
    /****************
       pl/sql程序单元
       是数据库中命名的pl/sql块,作为数据库对象保存在数据库里。
       存储过程:执行特定的操作,没有返回值。
       函数:进行复杂的运算,有返回值。
       包:相当于java中的类,可以在里面定义变量常量方法(存储过程,函数等)
    ***********************/
    create or replace procedure firstPro
    is
       
    begin
      --向tb_student中插入一条数据
      insert into tb_student(id,lastname,age,sex,email,address,class_id,course_id,great)
      values(tb_student_seq.nextval,'爸爸',46,'男','123888@qq.com','南昌',1,2,98);
      commit;
      end firstPro;
    --存储过程执行只是编译只有调用时才是执行了  他作为pl/sql存储单元,作为数据库对象保存在数据库中
    --调用存储过程
    declare 
    begin
      firstPro;
      end;
    select * from tb_student;
    
    --有参数的存储过程
    create or replace procedure paraPro
    (
      v_lastname varchar2,
      v_age number,
      v_sex varchar2,
      v_email varchar2,
      v_address varchar2,
      v_class_id number,
      v_course_id number,
      v_great number
    ) 
    is
    begin
      insert into tb_student(id,lastname,age,sex,email,address,class_id,course_id,great)
      values(tb_student_seq.nextval,v_lastname,v_age,v_sex,v_email,v_address,v_class_id,v_course_id,v_great);
      commit;
      end paraPro;
      
    --调用有参存储过程
    declare
    begin
      paraPro('fwppr',24,'男','123343dddd@qq.com','北京',1,2,97);
      end; 
    select * from tb_student;
    create sequence seq_tb_student;
    
    --练习
    /*******************
      存储过程更过情况下实在数据库方做数据整合等复杂的工作,现在在开发银行系统,数据相当重要   tb_student代替一张重要的
      表把表中的数据备份
      
      备份每天的表的数据
    **************************/
    /**********
       思路:首先你要知道见几张表才能完成这个备份工作
       1.你要备份得有一张备份表
       2.备份的条件是什么呢?每天的12点进行备份
       那么就是每天存储的主键id最大的时候为临界点
       所以又需要一张表来进行存储每天最大的主键id值并且每天必须更新
       3.存储过程的参数就为每天主键最大的id值
    **************/
    create or replace procedure backShuju
    (v_max number)
    is
    cursor c_tb_student is
    select * from tb_student where id>v_max;
    v_back_tb_student tb_student%rowtype;
    a number:=0;
    v_maxid number;
    begin
      --判断游标是否打开
      if(c_tb_student%isopen) then
      null;
      else
        open c_tb_student;
        end if;
     loop
     fetch c_tb_student into v_back_tb_student;
     exit when c_tb_student%notfound;
     insert into tb_student_back(id,lastname,age,sex,email,address,class_id,course_id,great)
     values(v_back_tb_student.id,v_back_tb_student.lastname,v_back_tb_student.age,v_back_tb_student.sex,
     v_back_tb_student.email,v_back_tb_student.address,v_back_tb_student.class_id,v_back_tb_student.course_id,v_back_tb_student.great);
     a:=a+1;
     /***
       1.如果在循环中commit效率低下
       2.如果数据量很大,没有commit就没有提交,放在缓存当中。缓存就是内存当中,在oracle回滚段不足导致瘫痪
     ****/
     if(a>=2000) then
     commit;
     a:=0;
     end if;
     end loop;
     commit;
     select max(id) into v_maxid from tb_student_back;
     update tb_max set id=v_maxid;
     close c_tb_student;
      end backShuju;
      
      
      
    --创建数据备份表
     create table tb_student_back as
     select * from tb_student where id=-1;
     --创建存储每天主键最大id表
     create table tb_max(
     id number
     );
     
    --创建调用备份存储过程的存储过程
    create or replace procedure invokeBackShuju
    is
      v_max number;
    begin
      select id into v_maxid from tb_max;
      backShuju(v_max);
      end invokeBackShuju;
    select * from tb_student_back;
    select * from tb_student;
    select * from tb_max;
    insert into tb_max (id) values(0);
    drop table tb_max;
    drop table tb_student_back;
    begin
      invokeBackShuju;
      end;
    declare
    v_aa number:=2000;
    begin
      while (v_aa>=0) loop
      insert into tb_student(id,lastname,age,sex,email,address,class_id,course_id,great)
      values(tb_student_seq.nextval,'许洁'||v_aa,46,'男','1s8822'||v_aa||'qq.com','南昌',1,2,98);
      v_aa:=v_aa-1;
      end loop;
      commit;
      end;
      
      
    --创建任务调度器
    declare
    jobno number;
    begin
      dbms_job.submit(
      jobno,
      what=>'invokeBackShuju;',--为存储过程的名称
      Interval=>'trunc(sysdate,''mi'')+1/(24*60)'
      );
      commit;
      end;
     
    
    --实验游标和%rowtype的功能区别
    --%rowtype最多只能提取一条数据
    --游标可以提取多条数据
    --下面语句错误
    declare
    r_tb_student tb_student%rowtype;
    begin
      select * into r_tb_student from tb_student;
      end;
    
    
    
    --函数和包
    --无参函数
    create or replace function firstfun return varchar2
    is
    begin
      return '许洁是傻逼';
      end firstfun;
      
    --调用函数
    declare
    begin
      dbms_output.put_line(firstfun());
      end;
    --有参函数
    create or replace function parafun(v_para number)return number is
    begin
      return v_para*12;
      end parafun;
      
      
    --调用有参函数
    declare 
      v_sal emp.sal%type;
    begin
      select sal into v_sal from emp where empno=7499;
      dbms_output.put_line(parafun(v_sal));
      end;
      
      
    select * from emp;
    
    --包
    --相当于java中的接口
    --包体相当于接口方法的实现类
    create or replace package firstpage is
      --在包中定义一个type类型的变量
      type strings is array;
      --定义一个常量
      i constant number:=1;
      --定义一个过程
      procedure secondPro;
      --定义一个函数
      function secondfun(v_max number) return number;
    end firstpage;
    
    create or replace package body firstpage is
      function secondfun(v_max number) return number is
        begin
          return v_max*12; 
          end;
      procedure secondPro is
        begin
          insert into tb_clazz(id,code) values(tb_clazz_seq.nextval,'ddddd');
          commit;
          end;
    end firstpage;
    
    
    --调用包
    declare 
      v_sal emp.sal%type;
    begin
      select sal into v_sal from emp where empno=7499;
      dbms_output.put_line('年薪》》'||firstpage.secondfun(v_sal));
      firstpage.secondPro;
      end;
    select * from tb_clazz;
    

    触发器(相当于js当中的事件  只要触发了那个事件,下面的代码就会执行)

    触发器中不能提交

    因为触发器是跟着数据走的,如果提交了完成触发器的执行之后想要回滚将不可以

    什么是触发器?

    触发器在数据库里以独立的对象存储,他和存储过程是不一样的  ,存储过程是通过被调用才执行,而触发器使用过某次事件发生了,根据事件有没有发生来决定他是否执行

    1.dml触发器      

    相当于一个dml语句影响到了多条sql语句,对于数据库的每个数据行,只要它符合触发的条件,那么触发器将被激活一次,这是行级触发器

    语句级触发器   

    将整个语句操作为触发事件,让符合约束条件,激活一次触发器

    create  or replace  tirgger 名

    after  delete on  tb_clazz  --在tb_clazz表执行删除操作时,触发这个事件

    referenceing  olg as myold new as mynew--说明相关名称      触发器的pl/sql中应用相关名称时必须在她们之前加冒号:;但是在when子句中不能加冒号

    for each row

    declare

    begin

    end

    :new   访问操作完成后的值 

    :old    访问操作完成之前的值

    2.替代触发器

    不能对由两个以上的表建立的视图进行操作。所以给出了替代触发器;专门为进行视图操作的一种处理方法

    3.系统触发器

    创建这个触发器需要一个权限

    administer database trigger

    系统触发器时间表  logging_event

    event:=sysevent

    type:=dictionary_obj_type   对象的类型

    name:=dictionary_obj_name  对象的名称

    owner:=dictionary_obj_owner  对象的拥有者  也就是哪个用户

    create  or replace trigger 触发器名

    after  login database

    declare

    begin

    end;

    --触发器
    --在触发器中不用提交
    create or replace trigger firstTrigger
    after delete /* or update*/on tb_clazz
    referencing new as mynew old as myold
    for each row--行级触发
    declare
    v_str tb_clazz%rowtype;
    begin
      v_str.id:=:myold.id;
      v_str.code:=:myold.code;
      dbms_output.put_line(v_str.id);
      dbms_output.put_line(v_str.code);
      insert into tb_clazz_back (id,code) values(v_str.id,v_str.code);
      --触发器中不能提交   
      --触发器是跟着数据走的,在触发器中commit的话触发器中的sqlcommit了,而且他监听的delete也commit了,所以想
      --会滚时就不可以了
      end;
    insert into tb_clazz(id,code) values(9,'111');
    select * from tb_clazz;
    delete from tb_clazz where id=9;
    select * from tb_clazz_back;
    create table tb_clazz_back as select * from tb_clazz where id=9999999;
    
    
       drop table logging_event;
    
    --系统级触发器
    --赋予创建任何触发器的权限
    grant create any trigger to scott;
    grant create trigger to scott;
    --授予管理数据库触发器的权限
    grant administer database trigger to scott;
      create table scott.logging_event(
       username varchar2(20),
       logintime date
       );
    --创建登录记录时候的备份
    create or replace trigger XiTongTri 
    after logon on database
    declare 
    begin
       insert into scott.logging_event(username,logintime) values(USER,sysdate);
       commit;
      end;
    select * from logging_event;
    
    drop table loggin_event2 purge;
    create table loggin_event3(username varchar2(20),tablename varchar2(20));
    create or replace trigger deleteTri
    after create on database
    declare
        tablename varchar2(20);
    begin
       tablename:=dictionary_obj_name;
       insert into loggin_event3(username,tablename) values(user,tablename);
       --在触发器中不能commit;
      end;
      create table tb_test_1(a number);
      select * from loggin_event3;
    

      

  • 相关阅读:
    C#等同于正则表达式的写法
    操作XML
    对比工具集合
    IIS 部署的网站无法启动
    jdk_1.8 下载之后的配置
    sql server 2008认识 DENSE_RANK
    c# 二分查找算法
    c# 使用栈实现有效的括号
    sql server 自定义标量函数
    虚拟机cenos 重置密码
  • 原文地址:https://www.cnblogs.com/fupengpeng/p/7528291.html
Copyright © 2020-2023  润新知