Oracle的触发器Trigger

参考:https://blog.csdn.net/weixin_41649106/article/details/86981325
https://blog.csdn.net/htj10/article/details/114629358
Oracle 触发器详解(trigger)

触发器的应用场景

  1. 复杂的安全性检查
  2. 数据的确认
  3. 数据库审计
  4. 数据的备份和审计

触发器例子1:update 之前进行安全检查

准备工作:

create table t_salary(id number(8), sal number(10,2));
insert  into t_salary(id, sal) values(1, 8000);
select * from t_salary;

 创建触发器:

/**
涨后的薪水不能低于涨前的薪水
1 :old 和 :new 代表同一条记录
2 :old 代表操作该行之前,这一行的值
 :new 代表操作该行之后,这一行的值
*/
create or replace trigger checkSalary
 before update
 on t_salary
 for each row
declare
 -- local variables here 没有变量声明的话,declare可以省略
begin
 -- if 涨后的薪水 < 涨前的薪水 then 如何表示呢 ?
 if :new.sal < :old.sal then
   raise_application_error(-20002,'涨后的薪水:'|| :new.sal ||'小于涨前的薪水:'||:old.sal);
 end if;
end checkSalary;

 测试:

SQL> update t_salary set sal=7000 where id=1;
update t_salary set sal=7000 where id=1
       *
第 1 行出现错误:
ORA-20002: 涨后的薪水:7000小于涨前的薪水:9000
ORA-06512: 在 "SCOTT.CHECKSALARY", line 6
ORA-04088: 触发器 'SCOTT.CHECKSALARY' 执行过程中出错

 删除触发器

--删除 触发器
drop trigger checkSalary;

 例子2:备份数据

/*
删除前,将数据备份
*/
create or replace trigger tri_sal_delete_bk
  before delete
  on t_salary
  for each row
begin
  insert into t_salary_del(id,sal) values(:old.id, :old.sal);
  -- commit; -- 注意不可以有提交,会报错ora-04092
end tri_sal_delete_bk;

 注意:DML(delete/update/insert)触发器中不能使用DDL(CREATE,DROP,ALTER)语句,也不能使用事务控制语句(ROLLBACK, COMMIT,SAVEPOINT)。特别注意的是,在触发器的主体中引用的函数(function)/过程(procedure)中也不能有事物控制语句。

例子3:非工作时间禁止插入数据

/**
非工作时间(星期六 星期日, 非9点~18点的区间)禁止写入数据
首先要搞清楚: 触发器的类型--语句级触发器。
不管插入了多少条数据,没有必要对每一行数据都进行校验,只要不在这个时间段内,都不让插入。
*/

create or replace trigger tri_addSalaryCheck
  before insert on t_salary
declare
 -- local variables here
begin
  if to_char(sysdate, 'day') in ('星期六', '星期日') or
      to_number(to_char(sysdate, 'hh24')) not between 9 and 18    then
      -- 禁止insert
      raise_application_error(-20001,'非工作时间禁止插入数据');
  end if;
end tri_addSalaryCheck;

例子4:Oracle实现像Mysql的自动增长auto_increment

-- 建表:
CREATE TABLE t_user(U_ID NUMBER(8), UNAME VARCHAR2(20), UPASSWORD VARCHAR2(20));

-- 建立序列:
CREATE SEQUENCE SEQ_TUSER  
INCREMENT BY 1
MINVALUE 1                      --最小值  
MAXVALUE 99999999               --最大值由NUMBER(8)  
NOCYCLE                              --不打环   
NOCACHE                              --不缓存  
ORDER;
COMMIT;  

-- 然后建立before的触发器:
CREATE OR REPLACE TRIGGER TRG_ADDTUSER  
BEFORE INSERT ON t_user
FOR EACH ROW
BEGIN
SELECT SEQ_TUSER.NEXTVAL INTO :NEW.U_ID FROM DUAL;
END TRG_ADDTUSER;

-- 测试:
INSERT INTO t_user (UNAME,UPASSWORD) VALUES ('libai','589avf');
INSERT INTO t_user (UNAME,UPASSWORD) VALUES ('zhangsan','ko098');
COMMIT;
select * from t_user;

例子5:插入或更新或删除 后 触发

CREATE OR REPLACE TRIGGER trigger_table01 
AFTER INSERT OR UPDATE OR DELETE ON table01
 FOR EACH ROW
  
DECLARE recordNum INT;
BEGIN
  IF (inserting OR updating) THEN
    SELECT COUNT(1) INTO recordNum FROM table02 WHERE name=:NEW.USER_NAME;
    IF (recordNum =0) THEN
      EXECUTE IMMEDIATE 'insert into table02(name) values ('''||:NEW.USER_NAME||''') ';
    END IF;
  ELSIF DELETING THEN
    EXECUTE IMMEDIATE 'delete from table02 where name = '''||:OLD.USER_NAME||''' ';
  END IF;
END;

常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
原文地址:https://www.cnblogs.com/htj10/p/15238395.html