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