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
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
Triggering Statement | OLD.field Value | NEW.field Value |
|
|
Post-insert value |
|
Pre-update value |
Post-update value |
|
Pre-delete value |
|
: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; /
触发条件
before statement
before each row
after each row
after statement
FOLLOWS | PRECEDES子句
依赖关系: user_depenencies
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;
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; /
\
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
.
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 /
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相比,触发发动作仅仅提供事件,动作本身没有效果
例如普通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会再区分为schema和database的trigger
本质上都是trigger的事件的不同。
ddl event/database_event:
原文:https://www.cnblogs.com/fqguo24/p/12896576.html