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;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容