• Oracle Day8


    本节内容

      1.自定义函数

      2.存储过程

      3.游标

      4.触发器

    一、自定义函数

           函数:是一个PL/SQL的程序块,保存在数据库中,必须有一个返回值。

         

     create [or replace] function function_name
      [(parameter_list)]
      return datatype
      {is/as}
      [local_declarations]
      begin
        executable_statements;
      [exception_handlers;]
      end;
      说明:
      function_name:函数名称。
      parameter_list:函数列表,可选。
      return datatype:指定函数的返回类型,不能指定大小。
      local_declarations:局部变量声明,可选。
      executable_statements:要执行的PL-SQL语句。
      exception_handlers:异常处理,可选。
      or repalce:是否覆盖,可选。
    

     2个数比较大小的函数 

    create or replace function function1(para1 in number, para2 in number)   
    return number   
    as   
    begin  
      if para1 > para2 then  
          return para1;  
      else  
          return para2;   
      end if;  
    end function1; 
    

     删除函数:

        

    drop  function 函数名
    

      

    二、存储过程

          存储过程是一种命名的pl/sql程序块可以接收多个或零个输入、输出参数,提高sql语句的功能与灵活性,存储过程编译后存储在数据库中,使用时直接调用即可

    所谓存储过程(Stored Procedure),就是一组用于完成特定数据库功能的SQL语句集,该SQL语句集经过
    编译后存储在数据库系统中。在使用时候,用户通过指定已经定义的存储过程名字并给出相应的存储过程参数
    来调用并执行它,从而完成一个或一系列的数据库操作

    创建存储过程

         Oracle存储过程包含三部分:过程声明,执行过程部分,存储过程异常

    create or replace procedure NoParPro  
     as  //声明  
     ;  
     begin // 执行  
     ;  
     exception//存储过程异常  
     ;  
     end; 
    

      

     create or replace procedure p_dept
        is
          --声明变量
          d_name departments.department_name%type;
         
        begin
          
        select department_name into d_name from departments where department_id=10;
         
        dbms_output.put_line(d_name);
        
        end; 
        
        
        --使用
        
          begin
            
            p_dept();
            end;
            
            
                 
        create or replace procedure insert_dept(d_name in varchar2,m_id in number,lo_id in number)
        is
          
         
        begin
          
         insert into departments  
         values(departments_seq.nextval,d_name,m_id,lo_id);
         
         
         commit;
        exception
          when others then
            rollback;
        
        end; 
               
            
        
        --调用 
        declare
        d_name departments.department_name%type:=&d_name;
        m_id departments.manager_id%type:=&m_id;
        lo_id departments.location_id%type:=&lo_id;
        begin
          
        insert_dept(d_name,m_id,lo_id);
        
        end;
        
        
        
                
        
      select * from departments  
        
        
    
    
    create or replace procedure d_dept(d_id in number,lo_id out number)
    is
    begin
      select location_id into lo_id from departments where department_id=d_id;
      
    end; 
    
    
      --调用
      declare
       d_id departments.department_id%type:=&d_id;
       lo_id departments.location_id%type;
      begin
        
       d_dept(d_id,lo_id);
       
       dbms_output.put_line(lo_id);
      end; 
    
    create or replace procedure dp_dept(a in out number)
    is
    begin
       select a*a into a from dual;
      
    end; 
    
     declare
     a number:=&a;
     begin
       dp_dept(a);
      dbms_output.put_line(a);
      end;
      
      
    

    删除存储过程

      

    drop  PROCEDURE 存储过程名
    

      

    三、游标

        游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率

    游标有两种类型:显式游标和隐式游标。在前述程序中用到的SELECT...INTO...查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标对应一个返回结果为多行多列的SELECT语句。 

    游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。 

    隐式游标 
    如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是: 
    * 插入操作:INSERT。 
    * 更新操作:UPDATE。 
    * 删除操作:DELETE。 
    * 单行查询操作:SELECT ... INTO ...。 
    当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标的属性有四种,如下所示

    隐式游标的属性 返回值类型   意    义   
    SQL%ROWCOUNT    整型  代表DML语句成功执行的数据行数   
    SQL%FOUND   布尔型 值为TRUE代表插入、删除、更新或单行查询操作成功   
    SQL%NOTFOUND    布尔型 与SQL%FOUND属性返回值相反   
    SQL%ISOPEN  布尔型 DML执行过程中为真,结束后为假  
    

    显示游标的处理:

     定义游标:就是定义一个游标名,以及与其相对应的SELECT 语句 ,其一般形式为:
       CURSOR cursor_name IS  select_statement;

    游标声明部分是唯一可以出现在模块声明部分的步骤,其他三个步骤都在执行和异常处理部分中
    游标名是标识符,所以也有作用域,并且必须在使用前进行说明
     任何SELECT语句都是合法的,但是SELECT …INTO语句是非法的

    1.打开游标

        打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。
    OPEN cursor_name
    PL/SQL 程序不能用OPEN 语句重复打开一个游标

    2.提取游标
     

    提取游标:就是检索结果集合中的数据行,放入指定的输出变量中。
    FETCH cursor_name INTO {variable_list | record_variable }
    

    3.关闭游标

    关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。
    CLOSE cursor_name
    

      

    --游标:是一种命名的工作区并操作其中信息的一种机制
    --游标:显式游标: 所有的查询语句都是显式有标
      --    隐式游标: 非查询语句
      
    --显式游标处理
      --处理游标  首先定义游标
      
      declare
         dept departments%rowtype;
         --1.定义游标
         cursor dept_cur is select * from departments;
       begin
         --2.打开游标
         open dept_cur;
           if dept_cur%isopen then
           dbms_output.put_line('游标打开');
           end if;
         --3.操作: 提取数据
         loop 
         fetch dept_cur into dept;
          exit when dept_cur%notfound;
         dbms_output.put_line(dept.department_id||' '
         ||dept.department_name||'  '||dept.manager_id||
         '   '||dept.location_id);
       
          end loop;
          dbms_output.put_line(dept_cur%rowcount);
         --4.关闭游标
         close dept_cur;
    
       end;
    

     游标 for循环 

      PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。
    FOR index_variable IN cursor_name[value[, value]…] LOOP
     -- 游标数据处理代码
    END LOOP;

        

     declare
         
         --1.定义游标
         cursor dept_cur is select * from departments;
       begin
         
        for dept in  dept_cur loop
            if dept_cur%isopen then
           dbms_output.put_line('游标打开');
           end if;
          dbms_output.put_line(dept.department_id||' '
         ||dept.department_name||'  '||dept.manager_id||
         '   '||dept.location_id);
        
        
        end loop;
      
       end;
    

      

    四、触发器

          触发器在数据库里以独立的对象存储,它与存储过程不同的是,存储过程通过其它程序来启动运行或直接启动运行,而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且,触发器不能接收参数。所以运行触发器就叫触发或点火
    ORACLE事件指的是对数据库的表进行的INSERT、UPDATE及DELETE操作或对视图进行类似的操作。ORACLE将触发器的功能扩展到了触发ORACLE,如数据库的启动与关闭等。

    触发器分类:

    系统触发器
         它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等。
     DML触发器 :
        ORACLE可以在DML语句进行触发,可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发 。
     替代触发器:
             由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE专门为进行视图操作的一种处理方法
     
    触发器组成:
    触发器的组成主要有:
    触发事件:即在何种情况下触发TRIGGER; 例如:INSERT, UPDATE, DELETE。
    触发时间:即该TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该TRIGGER 的操作顺序。
    触发器本身:即该TRIGGER 被触发之后的目的和意图,正是触发器本身要做的事情。 例如:PL/SQL 块。
    触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。 
           语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次;
           行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。
     
     

    编写触发器时,需要注意以下几点:

             触发器不接受参数。

             一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。

             在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。

           触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用。

             在触发器的执行部分只能用DML语句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL语句(CREATE、ALTER、DROP)

             触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。

            在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。

            在触发器主体中不能申明任何Long和blob变量。新值new和旧值old也不能是表中的任何long和blob列。

             不同类型的触发器(如DML触发器、INSTEAD OF触发器、系统触发器)的语法格式和作用有较大区别。

     

    创建触发器语法:

        

    CREATE [OR REPLACE] TRIGGER trigger_name
    {BEFORE | AFTER }
    {INSERT | DELETE | UPDATE [OF column [, column …]]}
    [OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
    ON [schema.]table_name | [schema.]view_name 
    [REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
    [FOR EACH ROW ]
    [WHEN condition]
    PL/SQL_BLOCK | CALL procedure_name;
    

      

    其中:

    BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。

           FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操作影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则只能为行触发器。

               REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。

    WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。

        当一个基表被修改( INSERT, UPDATE, DELETE)时要执行的存储过程,执行时根据其所依附的基表改动而自动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。

     

    系统触发器:

        

    --系统触发器:  数据库启动以及关闭    数据库启动时间以及关闭时间保存下来
      --创建触发器
      
      create table db_time(dbstrattime date);
      
      
      create or replace trigger db_trigger
           
        after startup on database
        
        begin
            
          insert into  db_time values(sysdate);
          
        
          end;
    

      

    DML触发器

      

    DML触发器的限制

    l         CREATE TRIGGER语句文本的字符长度不能超过32KB;

    l         触发器体内的SELECT 语句只能为SELECT … INTO …结构,或者为定义游标所使用的SELECT 语句。

    l         触发器中不能使用数据库事务控制语句 COMMIT; ROLLBACK, SVAEPOINT 语句;

    l         由触发器所调用的过程或函数也不能使用数据库事务控制语句;

    l         触发器中不能使用LONG, LONG RAW 类型;

    l         触发器内可以参照LOB 类型列的列值,但不能通过 :NEW 修改LOB列中的数据;

     

    DML触发器基本要点

    l         触发时机:指定触发器的触发时间。如果指定为BEFORE,则表示在执行DML操作之前触发,以便防止某些错误操作发生或实现某些业务规则;如果指定为AFTER,则表示在执行DML操作之后触发,以便记录该操作或做某些事后处理。

    l         触发事件:引起触发器被触发的事件,即DML操作(INSERT、UPDATE、DELETE)。既可以是单个触发事件,也可以是多个触发事件的组合(只能使用OR逻辑组合,不能使用AND逻辑组合)。

    l         条件谓词:当在触发器中包含多个触发事件(INSERT、UPDATE、DELETE)的组合时,为了分别针对不同的事件进行不同的处理,需要使用ORACLE提供的如下条件谓词。

    1)。INSERTING:当触发事件是INSERT时,取值为TRUE,否则为FALSE。

    2)。UPDATING [(column_1,column_2,…,column_x)]:当触发事件是UPDATE      时,如果修改了column_x列,则取值为TRUE,否则为FALSE。其中column_x是可选的。

    3)。DELETING:当触发事件是DELETE时,则取值为TRUE,否则为FALSE。

    解发对象:指定触发器是创建在哪个表、视图上。

    l         触发类型:是语句级还是行级触发器。

    l         触发条件:由WHEN子句指定一个逻辑表达式,只允许在行级触发器上指定触发条件,指定UPDATING后面的列的列表。

     

    问题:当触发器被触发时,要使用被插入、更新或删除的记录中的列值,有时要使用操作前、        后列的值.

    实现:  :NEW 修饰符访问操作完成后列的值

           :OLD 修饰符访问操作完成前列的值

     

     

    --DML触发器:  
    --增:  新数据
    --删:  旧数据
    --改: 新数据  旧数据
    
    
       create table dept as select * from departments where 1=0;
        
        
        create or replace trigger dept_trigger
        
         before update or delete  on hr.departments
         --行级触发
         for each row
           
         begin
           if deleting then
          
            insert into dept values(:old.department_id,:old.department_name,:old.manager_id,:old.location_id); 
           elsif updating then
              insert into dept values(:new.department_id,:new.department_name,:new.manager_id,:new.location_id); 
           end if;
         end;
         
         delete from departments where  department_id=120;
         
         update departments set department_name='人事部' where department_id=30
        select * from departments
        select * from dept
        delete from dept
    

    创建替代(INSTEAD OF)触发器

    CREATE [OR REPLACE] TRIGGER trigger_name
    INSTEAD OF
    {INSERT | DELETE | UPDATE [OF column [, column …]]}
    [OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
    ON [schema.] view_name --只能定义在视图上
    [REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
    [FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定
    [WHEN condition]
    PL/SQL_block | CALL procedure_name;
    

      

    其中:

               INSTEAD OF 选项使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立INSTEAD OF触发器,而不能对表、模式和数据库建立INSTEAD OF 触发器。

               FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则为行触发器。

               REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。

    WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。

     

        INSTEAD_OF 用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新

      

    create view emp_dept as select employee_id,last_name,salary,department_name from employees,departments where employees.department_id=departments.department_id;
        
        
      --替代触发器
      
          create or replace trigger emp_dept_trigger
          
          INSTEAD OF insert or delete on emp_dept 
          begin
           
           insert into employees values(:new.employee_id,'ewew',:new.last_name,'dsdes','111.111.11',sysdate,'AD_VP',:new.salary,null,120,30);
    
          end;
          
          
          insert into emp_dept values(300,'小刚',2000,'人事部');
          
          select * from employees
    

      

     
     
    删除触发器:
     
         
    DROP TRIGGER trigger_name; 
    

      

    触发器状态:

        有效状态(ENABLE):当触发事件发生时,处于有效状态的数据库触发器TRIGGER 将被触发。
     无效状态(DISABLE):当触发事件发生时,处于无效状态的数据库触发器TRIGGER 将不会被触发,此时就跟没有这个数据库触发器(TRIGGER) 一样。

      

    数据库TRIGGER的这两种状态可以互相转换。格式为: 
    	ALTER TIGGER trigger_name [DISABLE | ENABLE ]; 
    

      

    ALTER TRIGGER语句一次只能改变一个触发器的状态,而ALTER TABLE语句则一次能够改变与指定表相关的所有触发器的使用状态。格式为:
    ALTER TABLE [schema.]table_name {ENABLE|DISABLE} ALL TRIGGERS; 
    

      

     


      

            

     

  • 相关阅读:
    数据库优化
    List,map,Set区别
    ID选择器
    最简单的添加删除行操作
    JQ2
    最简单的JQ实现
    20180416
    一行细分的HTML写法
    out参数的使用
    结构的使用
  • 原文地址:https://www.cnblogs.com/wuzhilong/p/9481422.html
Copyright © 2020-2023  润新知