首页 > 其他 > 详细

PL学习-trigger

时间:2020-05-15 21:30:26      阅读:67      评论:0      收藏:0      [点我收藏+]

https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS020

note, 例子也来源此文档

功能上区分分为dml trigger,instead of trigger,  ddl trigger(schema trigger), databasee trigger

 

 

simple dml trigger

语法

技术分享图片

 

plsql_trigger_source

 

技术分享图片

simple_dml_trigger

 

技术分享图片

 

 

 

 

触发时机

before

after

触发事件

insert  ---> 对应INSERTING函数

delete  ---> 对应DELETING函数

update --> 对应UPDATING函数

update of column_list

 

Conditional Predicate TRUE if and only if:
INSERTING An INSERT statement fired the trigger.
UPDATING An UPDATE statement fired the trigger.
UPDATING (‘column‘) An UPDATE statement that affected the specified column fired the trigger.
DELETING A DELETE statement fired the trigger.

 

 

技术分享图片

行级与语句级触发器

for each row

不带for each row

伪记录

  1. 只有行级触发器才有伪记录
  2. 伪记录与触发触发器的语句的关系
Triggering Statement OLD.field Value NEW.field Value

INSERT

NULL

Post-insert value

UPDATE

Pre-update value

Post-update value

DELETE

Pre-delete value

NULL

 

:new

:old

oracle里有rowid

 

伪记录不能被赋值,传参。

但是伪记录的field可以传参数

 

:old伪记录的field不可以修改

:new伪记录的field可以被修改,前提是before。

 

:new和:old伪记录的rowid始终相等

 

new,old 和 parent伪列通过referencing改名字

技术分享图片

 

其实伪记录还有一个叫parent,用在视图的nested table column的触发器

-- Create type of nested table element:
 
CREATE OR REPLACE TYPE nte
AUTHID DEFINER IS
OBJECT (
  emp_id     NUMBER(6),
  lastname   VARCHAR2(25),
  job        VARCHAR2(10),
  sal        NUMBER(8,2)
);
/
 
-- Created type of nested table:
 
CREATE OR REPLACE TYPE emp_list_ IS
  TABLE OF nte;
/
 
-- Create view:

CREATE OR REPLACE VIEW dept_view AS
  SELECT d.department_id, 
         d.department_name,
         CAST (MULTISET (SELECT e.employee_id, e.last_name, e.job_id, e.salary
                         FROM employees e
                         WHERE e.department_id = d.department_id
                        )
                        AS emp_list_
              ) emplist
  FROM departments d;
 
-- Create trigger:
---instead of insert on nested table emplist of dept_view
 
CREATE OR REPLACE TRIGGER dept_emplist_tr
  INSTEAD OF INSERT ON NESTED TABLE emplist OF dept_view
  REFERENCING NEW AS Employee
              PARENT AS Department
  FOR EACH ROW
BEGIN
  -- Insert on nested table translates to insert on base table:
  INSERT INTO employees (
    employee_id,
    last_name,
    email,
    hire_date,
    job_id,
    salary,
    department_id
  )
  VALUES (
    :Employee.emp_id,                      -- employee_id
    :Employee.lastname,                    -- last_name
    :Employee.lastname || ‘@company.com‘,  -- email
    SYSDATE,                               -- hire_date
    :Employee.job,                         -- job_id
    :Employee.sal,                         -- salary
    :Department.department_id              -- department_id
  );
END;
/

  

 

when子句

触发条件

  1. 新伪记录和旧伪记录不用带:
  2. 需要()将逻辑表达式括起来
  3. 只能用SQL函数

 

触发器执行的顺序

  1. 没有follow或者precedes子句

before statement

before each row

after each row

after statement

 

FOLLOWS | PRECEDES子句

 

依赖关系: user_depenencies

 

事务

  1. 一般情况下为触发的dml事务的一部分,trigger里不能有commit和rollback
  2. 异常,事务回滚
  3. 如果开启自治事务,是可以rollback和commit

PRAGMA AUTONOMOUS_TRANSACTION;

突变表错误

ORA-04091

The mutating-table restriction prevents the trigger from querying or modifying the table that the triggering statement is modifying.

不让触发器查询或者修改(触发语句正在修改的)表

When a row-level trigger encounters a mutating table, ORA-04091 occurs, the effects of the trigger and triggering statement are rolled back, and control returns to the user or application that issued the triggering statement, as Example 9-26 shows.

当一个行级触发器发生突变表错误,受影响的触发器和触发语句回滚

控制返回给用户或者应用

 

-- Create log table
 
DROP TABLE log;
CREATE TABLE log (
  emp_id  NUMBER(6),
  l_name  VARCHAR2(25),
  f_name  VARCHAR2(20)
);
 
-- Create trigger that updates log and then reads employees
 
CREATE OR REPLACE TRIGGER log_deletions
  AFTER DELETE ON employees
  FOR EACH ROW
DECLARE
  n INTEGER;
BEGIN
  INSERT INTO log VALUES (
    :OLD.employee_id,
    :OLD.last_name,
    :OLD.first_name
  );
 
  SELECT COUNT(*) INTO n FROM employees;
  DBMS_OUTPUT.PUT_LINE(‘There are now ‘ || n || ‘ employees.‘);
END;
/
 
-- Issue triggering statement:
 
DELETE FROM employees WHERE employee_id = 197;

  

 

  1. 行级触发器不应该去读或者写(导致它被触发的)表的内容。语句级触发器没有这个限制
  2. 如果触发器使用自治事务(在trigger中commit)可以读表的内容,但是不能写

 

 

CREATE OR REPLACE TRIGGER t
  BEFORE
    INSERT OR
    UPDATE OF salary, department_id OR
    DELETE
  ON employees
BEGIN
  CASE
    WHEN INSERTING THEN
      DBMS_OUTPUT.PUT_LINE(‘Inserting‘);
    WHEN UPDATING(‘salary‘) THEN
      DBMS_OUTPUT.PUT_LINE(‘Updating salary‘);
    WHEN UPDATING(‘department_id‘) THEN
      DBMS_OUTPUT.PUT_LINE(‘Updating department ID‘);
    WHEN DELETING THEN
      DBMS_OUTPUT.PUT_LINE(‘Deleting‘);
  END CASE;
END;
/

  

 

 

trigger_body

技术分享图片\

The PL/SQL block or CALL subprogram that the database runs to fire the trigger. A CALL subprogram is either a PL/SQL subprogram or a Java subprogram in a PL/SQL wrapper.

If trigger_body is a PL/SQL block and it contains errors, then the CREATE [OR REPLACE] statement fails.

Restriction on trigger_body The declare_section cannot declare variables of the data type LONG or LONG RAW.

compound dml trigger

语法

技术分享图片

技术分享图片

plsql_trigger_source

 

技术分享图片

 

compound_trigger_block

技术分享图片

 

timing_point_section

 

技术分享图片

技术分享图片

 

tps_body

技术分享图片

 

 

例子

CREATE TABLE employee_salaries (
  employee_id NUMBER NOT NULL,
  change_date DATE   NOT NULL,
  salary NUMBER(8,2) NOT NULL,
  CONSTRAINT pk_employee_salaries PRIMARY KEY (employee_id, change_date),
  CONSTRAINT fk_employee_salaries FOREIGN KEY (employee_id)
    REFERENCES employees (employee_id)
      ON DELETE CASCADE)
/
CREATE OR REPLACE TRIGGER maintain_employee_salaries
  FOR UPDATE OF salary ON employees
    COMPOUND TRIGGER

-- Declarative Part:
-- Choose small threshhold value to show how example works:
  threshhold CONSTANT SIMPLE_INTEGER := 7;

  TYPE salaries_t IS TABLE OF employee_salaries%ROWTYPE INDEX BY SIMPLE_INTEGER;
  salaries  salaries_t;
  idx       SIMPLE_INTEGER := 0;

  PROCEDURE flush_array IS
    n CONSTANT SIMPLE_INTEGER := salaries.count();
  BEGIN
    FORALL j IN 1..n
      INSERT INTO employee_salaries VALUES salaries(j);
    salaries.delete();
    idx := 0;
    DBMS_OUTPUT.PUT_LINE(‘Flushed ‘ || n || ‘ rows‘);
  END flush_array;

  -- AFTER EACH ROW Section:

  AFTER EACH ROW IS
  BEGIN
    idx := idx + 1;
    salaries(idx).employee_id := :NEW.employee_id;
    salaries(idx).change_date := SYSDATE();
    salaries(idx).salary := :NEW.salary;
    IF idx >= threshhold THEN
      flush_array();
    END IF;
  END AFTER EACH ROW;

  -- AFTER STATEMENT Section:

  AFTER STATEMENT IS
  BEGIN
    flush_array();
  END AFTER STATEMENT;
END maintain_employee_salaries;
/
/* Increase salary of every employee in department 50 by 10%: */

UPDATE employees
  SET salary = salary * 1.1
  WHERE department_id = 50
/

/* Wait two seconds: */

BEGIN
  DBMS_LOCK.SLEEP(2);
END;
/

/* Increase salary of every employee in department 50 by 5%: */

UPDATE employees
  SET salary = salary * 1.05
  WHERE department_id = 50
/

  

 

compound + instead of trigger

  

CREATE trigger FOR dml_event_clause ON view
COMPOUND TRIGGER
INSTEAD OF EACH ROW IS BEGIN
  statement;
END INSTEAD OF EACH ROW;

  

 

instead of trigger

语法

技术分享图片

 

 

instead of表示改写

同普通的trigger相比,触发发动作仅仅提供事件,动作本身没有效果

 

例如普通delete 触发器,delete sql除了会执行trigger的动作外,本身会删除数据

instead of触发器,delete sql, 只会执行trigger的动作,并不执行delete操作

 

例子

CREATE OR REPLACE VIEW order_info AS
   SELECT c.customer_id, c.cust_last_name, c.cust_first_name,
          o.order_id, o.order_date, o.order_status
   FROM customers c, orders o
   WHERE c.customer_id = o.customer_id;

CREATE OR REPLACE TRIGGER order_info_insert
   INSTEAD OF INSERT ON order_info
   DECLARE
     duplicate_info EXCEPTION;
     PRAGMA EXCEPTION_INIT (duplicate_info, -00001);
   BEGIN
     INSERT INTO customers
       (customer_id, cust_last_name, cust_first_name)
     VALUES (
     :new.customer_id,
     :new.cust_last_name,
     :new.cust_first_name);
   INSERT INTO orders (order_id, order_date, customer_id)
   VALUES (
     :new.order_id,
     :new.order_date,
     :new.customer_id);
   EXCEPTION
     WHEN duplicate_info THEN
       RAISE_APPLICATION_ERROR (
         num=> -20107,
         msg=> Duplicate customer or order ID);
   END order_info_insert;
/

 

 

系统视图

user_triggers

dba_triggers

all_triggers

 

user_dependencies

 

System trigger

技术分享图片

 

一般System trigger会再区分为schema和database的trigger

本质上都是trigger的事件的不同。

 

ddl event/database_event:

https://docs.oracle.com/en/database/oracle/oracle-database/12.2/lnpls/CREATE-TRIGGER-statement.html#GUID-AF9E33F1-64D1-4382-A6A4-EC33C36F237B

 
 

PL学习-trigger

原文:https://www.cnblogs.com/fqguo24/p/12896576.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!