PL/SQL高级应用 触发器

之前所有创建的PL/SQL程序都是匿名的,没有为程序块提供一个名词, 这就无法被存储,每次只需后不可以被重复使用, 每次允许匿名块的时候都需要先编译,在执行,在很多时候为了提高系统的应用性能,需要数据库保存程序块,方便以后重复使用,这就意味着程序块需要一个名词

命名程序块: 过程, 函数, 程序包, 触发器。。。

存储过程

存储过程是用于执行特定操作
1. 创建
create [or replace] procedure procedure_name
[(paramater_name[in|out|in out] datatype[m],....])]

create or replace  procedure out_time
  is 
begin
  dbms_output.put_line('当前时间'||systimestamp);
  end;
drop procedure out_time;
  call out_time();
  1. 调用
    exec
    call

  2. 修改
    or replace

  3. 删除
    drop
    参数
    create or replace procedure add_dept
    (dno number, dname varchar2 default null, loc varchar2 default null)
    is
    begin
    insert into dept values(dno, dname,loc);
    end;

--drop procedure add_dept;
--call add_dept(13,'吃饭饿啊','新乡');

1. 位置传值
按照定义参数的顺序依次为参数指定响应的变量和值
call add_dept(50,loc => '你好')
  select * from dept;
参数模式
  1. in: 输入参数
  2. out: 输出参数
  3. in out : 输入输入出函数
    create or replace procedure pro_result (num1 in out number, num2 in out number)
    is
    v_result number(6,3);
    v_reamin number(6);
    begin
    v_result := num1/num2;
    v_reamin := mod(num1,num2);
    num1 := v_result;
    num2 := v_reamin;
    end;
    --drop procedure pro_result
    declare
    v_n1 number := 8;
    v_n2 number := 3;
    begin
    pro_result(num1 => v_n1,num2 => v_n2);
    dbms_output.put_line(v_n1||' '||v_n2);
    end;
函数 :
函数用于返回特定的数据,如果在应用程序中进程需要通过SQL语句来返回特定数据,可以创建函数和存储过程,存储过程

create or replace function get_name(eno number)
return varchar2
as
v_name emp.ename%type;
begin
select ename into v_name from emp where empno =eno;
return v_name;
end;

declare
str varchar2(30);
begin
str:= get_name(7788);
dbms_output.put_line('姓名: '||str);
end;

create or replace function get_workyear(hiredate in date)
return number
as
v_worlyear number := 0;
begin
v_worlyear := extract(year from sysdate) - extract(year from hiredate);
return v_worlyear;
end;

   select e.*, get_workyear(hiredate) workd from emp e; 

程序包

create or replace package pack_test
as
   v_temp number ;-- 定义全局
   procedure p1(x number);--定义存储过程
   end;
   create or replace package body pack_test
   as
   
   procedure p1(x number)
     as
     begin
       v_temp :=x;
       dbms_output.put_line(v_temp);
       end;
       end;

       begin
       pack_test.p1(44);
       end;  
       
create or replace package pack_emp is
procedure add_employee(eno number, name varchar2, salary number, dno number);
end;

  create or replace package body pack_emp is
-- 私有函数只能在包体中访问
   function validata_deptno(v_deptno number)
     return boolean
     is
     v_temp int;
     begin
       select count(deptno) into v_temp from dept where deptno = v_deptno;
       if v_temp >0 then
         return true;
       else
         return false;
       end if;
   end validata_deptno;

procedure add_employee(eno number, name varchar2, salary number, dno number)
is
begin
if validata_deptno(dno) then
  insert into emp(empno,ename,sal,deptno,hiredate) values(eno,name,salary,dno,sysdate);
  else
    raise_application_error(-20060,'部门不存在');
    end if;
    exception
      when dup_val_on_index then
        raise_application_error(-20430,'该员工已存在');
        end add_employee;
        end pack_emp;        
        begin
          pack_emp.add_employee(eno => 1002,name => '依恋',salary => 3400,dno => 20);
        end;
        select * from emp ;

create or replace package pack_overload
is
function get_sal(eno number) return number;
function get_sal(name varchar2) return number;

/*procedure del_employee(eno number);
procedure del_employee(name varchar2);*/

end;

create or replace package body pack_overload
is 
function get_sal(eno number) return number
is
v_sal emp.sal%type;
begin
    select sal into v_sal from emp where empno = eno;
    return v_sal;
    exception
      when no_data_found then
        raise_application_error(-2030,'该员工不存在');
end get_sal;
function get_sal(name varchar2) return number
is
v_sal emp.sal%type;
begin
    select sal into v_sal from emp where upper(ename) = upper(name);
    return v_sal;
    exception
      when no_data_found then
        raise_application_error(-2030,'该员工不存在');
end get_sal;
end pack_overload;

declare
v_sal number;
begin
v_sal:= pack_overload.get_sal('ALLEN');
dbms_output.put_line(v_sal);
end;
select * from emp;

包的构造

在包中定义全局变量,有些时候,会话中可能还需要初始化全局变量,可以通过包构造初始化
当在会话内第一次调用公共组件的时候,会自动执行其构造过程

声明: 在包体的最后 添加begin关键字, 后面编写构造内容

create or replace package pack_emptest is
minsal number(6,2);
maxsal number(6,2);
procedure update_sal(eno number, salary number);
end;

create or replace package body pack_emptest is
procedure update_sal(eno number, salary number)
  is
  begin
  dbms_output.put_line(minsal||'   '||maxsal);
  end update_sal;

  begin  
  select min(sal),max(sal) into minsal,maxsal from emp;
  dbms_output.put_line('构造被执行');
  end pack_emptest;

  begin
    pack_emptest.update_sal(7788,1);
end;

触发器

触发器(tigger)是一种特殊的类型的pl/sql块, 触发器类似于过程和函数, 也具有声明部分,执行部分, 异常部分, 触发器是在数据库事件发生时被隐式触发,而且触发器不能接受参数,不能像过程函数已有显示调用

触发器组成
触发事件: 引起触发器被触发的事件,例如DML语句(insert,update,delete)语句的时候对表或视图进行数据操作的时候触发, DDL事件(create,alter, drop),数据库事件(启动,退出,异常错误)用户事件(登录,退出)
触发的时间 :设置触发事件发生之前(before)还是之后(after)
触发对象: 包括 表,视图,模式,数据库, 只有在指定的对象上发生了特定的时间,才会被触发
触发条件: 是一个逻辑表达式
触发频率 : 设置语句基本的触发器还是行基本的触发器

触发器的类型
  1. DML触发器
    dml 所包含的事件 ,insert, update, delete DML语句触发器可以为这些触发事件创建, before(发生前)和after(发生后)触发器,DML触发器可以在语句级别或行级别操作上呗触发
    语句级别是对每一个SQL语句只触发一次,行级别对SQL影响的表中的每一行触发一次

  2. DDL触发器
    create。alter。drop

  3. 系统触发器
    login , logoff serverror 。startup, shutdown

  4. 替代触发器
    在对视图进行dml操作的时候执行的触发器

       create or replace trigger emp_count
       after delete on emp
       declare 
         v_con integer;
           begin
           select count(1) into v_con from emp;
       dbms_output.put_line('现在还有'||v_con||'行');
       end;
    
         select * from emp;
    
       delete from emp where empno = 1002; 
    

  create or replace trigger tri_emp
    before insert or update or delete on emp2
  begin
  if to_char(sysdate,'DY') in('星期六','星期日') then
  case
  when INSERTING then
    raise_application_error(-20006,'不能在休息日添加员工信息');
  when UPDATING then
    raise_application_error(-20006,'不能在休息日修改员工信息');
  when DELETING then
    raise_application_error(-20006,'不能在休息日删除员工信息');
  end case;
 end if;
 end;

 delete from emp2 where deptno =20;
 
 update emp2 set comm = 500 where empno = 7902;
 
 create table emp2 as select * from emp;
  select * from emp2

数据库触发器

create table event_table(
event varchar2(30),
  time date
)

create or replace tirgger tir_startup
  after startup on database
begin
insert into event_table values (ora_sysevent, sysdata);
end;

  create or replace tirgger tir_shutdown
    after shutdown on database
  begin
insert into event_table values (ora_sysevent, sysdata);
end;

create table log_table(
username varchar(20),
log_time data,
logoff_time date,
address varchar(20)
);

登录触发
  create ot replace trigger tir_login
after logon on database
begin
insert into log_table (username,log_time,address)
values(ora_login_user, sysdate,ora_client_ip_address)
end;

退出触发
create ot replace trigger tir_logoff
after logoff on database
begin
insert into log_table (username,logoff_time ,address)
values(ora_login_user, sysdate,ora_client_ip_address)
end;


DDL 触发器
create or replace trigger tir_ddl
after ddl on scott.schema
begin
...
insert into event_ddl values(ora_sysevent,ora_login_user,ora_obj_owner,ora_dirct_obj_type,sysdate);
end;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容