zoukankan      html  css  js  c++  java
  • 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;
    

      

  • 相关阅读:
    笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)
    VMware workstation安装
    Redis bigkey分析
    MySQL drop table 影响及过程
    MySQL 大表硬连接删除
    ES elasticsearch 各种查询
    ES elasticsearch 各种聚合
    ES elasticsearch 聚合统计
    ES elasticsearch 实现 count单字段,分组取前多少位,以地理位置中心进行统计
    MySQL行溢出、varchar最多能存多少字符
  • 原文地址:https://www.cnblogs.com/fupengpeng/p/7528291.html
Copyright © 2011-2022 走看看