Sie sind auf Seite 1von 10

General

Data Dictionary Views Related


To DDL Triggers
create trigger
System Privileges Related create any trigger
To Table Triggerstrigger$ administer database trigger
dba_trig all_trigg user_tri alter any trigger
gers ers ggers drop any trigger
-- before constraints are applied
Table Trigger Firing BEFORE INSERT
Options BEFORE UPDATE
BEFORE DELETE

-- after constraints are applied


AFTER INSERT
AFTER UPDATE
AFTER DELETE
Transaction Model Oracle transactions are atomic. No commit or rollback are allowed in a trigger.
32K - but you can call procedures and function in triggers to perform
Maximum trigger size
processing
 
Create Statement Level Triggers (the default)

Statement Level Trigger With A Single Action


CREATE OR REPLACE CREATE TABLE orders (
TRIGGER somecolumn VARCHAR2(20),
<trigger_name> numbercol  NUMBER(10),
[<ENABLE | DISABLE>] datecol    DATE);
<BEFORE | AFTER>
<ACTION> [OR CREATE OR REPLACE TRIGGER statement_level
<ACTION> OR BEFORE UPDATE
<ACTION>] ON orders
ON <table_name>
[FOLLOWS DECLARE
<schema.trigger_name>]  vMsg VARCHAR2(30) := 'Statement Level Trigger Fired';
BEGIN
DECLARE   dbms_output.put_line(vMsg);
 <variable definitions> END statement_level;
BEGIN /
  <trigger_code>
EXCEPTION set serveroutput on
  <exception clauses>
END <trigger_name>; INSERT INTO orders (somecolumn) VALUES ('ABC');
/
UPDATE orders SET somecolumn = 'XYZ';

CREATE OR REPLACE TRIGGER statement_level


AFTER INSERT OR UPDATE OR DELETE
ON orders

DECLARE
 vMsg VARCHAR2(30) := 'Statement Level Trigger Fired';
BEGIN
  IF INSERTING THEN
    dbms_output.put_line(vMsg || ' When Inserting');
  ELSIF UPDATING THEN
    dbms_output.put_line(vMsg || ' When Updating');
  ELSIF DELETING THEN
    dbms_output.put_line(vMsg || ' When Deleting');

1
  END IF;
END statement_level;
/

set serveroutput on

INSERT INTO orders (somecolumn) VALUES ('ABC');

UPDATE orders SET somecolumn = 'DEF' WHERE ROWNUM = 1;

DELETE FROM orders WHERE ROWNUM = 1;

Create Row Level Triggers


Note: AFTER row triggers create less UNDO than BEFORE row triggers so use AFTER when possible.

Row Level Trigger ... most common usage to provide a surrogate key from a sequence
CREATE OR REPLACE CREATE TABLE t (
TRIGGER rid NUMBER(5),
<trigger_name> col VARCHAR2(3));
[FOLLOWS
<schema.trigger_name>] ALTER TABLE t
[<ENABLE | DISABLE>] ADD CONSTRAINT pk_t
<BEFORE | AFTER> PRIMARY KEY (rid)
<ACTION> OR USING INDEX;
<ACTION> OR
<ACTION> CREATE SEQUENCE seq_t;
[OF
<column_name_list>] CREATE OR REPLACE TRIGGER row_level
ON <table_name> BEFORE INSERT
REFERENCING NEW AS ON t
<synonym> OLD AS FOR EACH ROW
<synonym> PARENT AS
<synonym> BEGIN
FOR EACH ROW   SELECT seq_t.NEXTVAL
  INTO :NEW.rid
DECLARE   FROM dual;
 <variable definitions>   dbms_output.put_line(:NEW.rid);
BEGIN END row_level;
  <trigger_code> /
EXCEPTION
  <exception clauses> INSERT INTO row_t (col) VALUES ('A');
END <trigger_name>; INSERT INTO row_t (col) VALUES ('B');
/ INSERT INTO row_t (col) VALUES ('C');

SELECT * FROM t;

CREATE OR REPLACE TRIGGER row_level


BEFORE UPDATE
ON orders
FOR EACH ROW

DECLARE
 vMsg VARCHAR2(30) := 'Row Level Trigger Fired';
BEGIN
  dbms_output.put_line(vMsg);
END row_level;
/

set serveroutput on

INSERT INTO orders (somecolumn) VALUES ('ABC');


INSERT INTO orders (somecolumn) VALUES ('ABC');
2
INSERT INTO orders (somecolumn) VALUES ('ABC');

SELECT * FROM orders;

UPDATE orders SET somecolumn = 'XYZ';

CREATE OR REPLACE TRIGGER statement_level


AFTER INSERT OR UPDATE OR DELETE 
ON orders
FOR EACH ROW

DECLARE
 vMsg VARCHAR2(30) := 'Row Level Trigger Fired';
BEGIN
  IF INSERTING THEN
    dbms_output.put_line(vMsg || ' On Insert');
  ELSIF UPDATING THEN
    dbms_output.put_line(vMsg || ' On Update');
  ELSIF DELETING THEN
    dbms_output.put_line(vMsg || ' On Delete');
  END IF;
END statement_level;
/

set serveroutput on

INSERT INTO orders (somecolumn) VALUES ('ABC');

UPDATE orders
SET somecolumn = 'ZZT';

DELETE FROM orders WHERE rownum < 4;

CREATE OR REPLACE TRIGGER of_clause


BEFORE UPDATE
OF numbercol
ON orders
FOR EACH ROW

DECLARE
 vMsg VARCHAR2(40) := 'Update Will Change numbercol Column';
BEGIN
  dbms_output.put_line(vMsg);
END of_clause;
/

set serveroutput on

UPDATE orders
SET numbercol = 8;

CREATE TABLE person (


fname VARCHAR2(15),
lname VARCHAR2(15));

CREATE TABLE audit_log (


o_fname   VARCHAR2(15),
o_lname   VARCHAR2(15),
n_fname   VARCHAR2(15),
n_lname   VARCHAR2(15),
chng_by   VARCHAR2(10),
chng_when DATE);
3
CREATE OR REPLACE TRIGGER referencing_clause
AFTER UPDATE
ON person
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
  INSERT INTO audit_log
  (o_fname, o_lname, n_fname, n_lname, chng_by, chng_when)
  VALUES
  (:OLD.fname, :OLD.lname, :NEW.fname, :NEW.lname, USER, SYSDATE);
END referencing_clause;
/

INSERT INTO person (fname, lname) VALUES ('Dan', 'Morgan');

SELECT * FROM person;


SELECT * FROM audit_log;

UPDATE person
SET lname = 'Dangerous';

SELECT * FROM person;


SELECT * FROM audit_log;

UPDATE person
SET fname = 'Mark', lname = 'Townsend';

SELECT * FROM person;


SELECT * FROM audit_log;
CREATE TABLE test (
testcol VARCHAR2(15));

INSERT INTO test VALUES ('dummy');

CREATE OR REPLACE TRIGGER follows_a


AFTER UPDATE
ON test
FOR EACH ROW
BEGIN
  dbms_output.put_line('A');
END follows_a;
/

CREATE OR REPLACE TRIGGER follows_b


AFTER UPDATE
ON test
FOR EACH ROW
BEGIN
  dbms_output.put_line('B');
END follows_b;
/

set serveroutput on

UPDATE test SET testcol = 'a';

CREATE OR REPLACE TRIGGER follows_b


AFTER UPDATE
ON test
FOR EACH ROW
FOLLOWS uwclass.follows_a 
BEGIN

4
  dbms_output.put_line('B');
END follows_b;
/

UPDATE test SET testcol = 'a';


 
Compound Triggers (new 11g)

Compound triggers allow for writing a single trigger incorporating STATEMENT and ROW LEVEL and
BEFORE and AFTER
CREATE TRIGGER CREATE TABLE test AS
<trigger_name> SELECT table_name, tablespace_name
FOR <triggering_event> FROM user_tables;
ON <table_name>
COMPOUND TRIGGER set serveroutput on

BEFORE STATEMENT IS CREATE OR REPLACE TRIGGER compound_trig


BEGIN FOR INSERT ON test
  ... COMPOUND TRIGGER
END BEFORE -------------------------------
STATEMENT; BEFORE STATEMENT IS
BEGIN
BEFORE EACH ROW IS   dbms_output.put_line('BEFORE STATEMENT LEVEL');
BEGIN END BEFORE STATEMENT;
  ... -------------------------------
END BEFORE EACH ROW; BEFORE EACH ROW IS
BEGIN
AFTER STATEMENT IS   dbms_output.put_line('BEFORE ROW LEVEL');
BEGIN END BEFORE EACH ROW;
  ... -------------------------------
END AFTER STATEMENT; AFTER STATEMENT IS
BEGIN
AFTER EACH ROW IS   dbms_output.put_line('AFTER STATEMENT LEVEL');
BEGIN END AFTER STATEMENT;
  ... -------------------------------
END AFTER EACH ROW; AFTER EACH ROW IS
END compound_trigger; BEGIN
/   dbms_output.put_line('AFTER ROW LEVEL');
END AFTER EACH ROW;
END compound_trig;
/

SELECT trigger_name, trigger_type


FROM user_triggers;

INSERT INTO test


(table_name, tablespace_name)
VALUES
('MORGAN', 'UWDATA');

Altering Triggers (all types)

Disable A Single Trigger


ALTER TRIGGER CREATE TABLE t (
<trigger_name> testcol VARCHAR2(20));
DISABLE;
CREATE OR REPLACE TRIGGER bi_t
BEFORE INSERT
ON t
BEGIN
  NULL;

5
END bi_t;

CREATE OR REPLACE TRIGGER bd_t


BEFORE DELETE
ON t
BEGIN
  NULL;
END bd_t;
/

SELECT trigger_name, status


FROM user_triggers;

ALTER TRIGGER bi_t DISABLE;

SELECT trigger_name, status


FROM user_triggers;

ALTER TABLE t DISABLE ALL TRIGGERS;

SELECT trigger_name, status


FROM user_triggers;

ALTER TRIGGER bd_t ENABLE;

SELECT trigger_name, status


FROM user_triggers;

ALTER TABLE t ENABLE ALL TRIGGERS;

SELECT trigger_name, status


FROM user_triggers;
ALTER TABLE <table_name> DISABLE ALL TRIGGERS;
See DISABLE Demo;
ALTER TRIGGER <trigger_name> ENABLE;
See DISABLE Demo;
ALTER TABLE <table_name> ENABLE ALL TRIGGERS;
See DISABLE Demo;
ALTER TRIGGER <trigger_name> RENAME TO <new_name>;
ALTER TRIGGER bi_t RENAME TO new_trigger_name;

SELECT trigger_name, status


FROM user_triggers;

Drop Trigger (all types)


Drop Trigger
DROP TRIGGER DROP TRIGGER new_trigger_name;
<trigger_name>;
Trigger With Autonomous Transaction

The same simple trigger as an autonomous transaction


ALTER TABLE audit_log
ADD (commentcol
VARCHAR2(50));

desc audit_log

CREATE OR REPLACE

6
TRIGGER
t_autonomous_tx
BEFORE INSERT
ON person

DECLARE
 PRAGMA
AUTONOMOUS_TRANSAC
TION;
BEGIN
  INSERT INTO audit_log
  (chng_when,
commentcol)
  VALUES
  (SYSDATE, 'Reporting
an error');
  COMMIT; 
END t_autonomous_tx;
/

INSERT INTO person


(fname) VALUES
('abcdefghijklmnopqrst');

SELECT * FROM person;


SELECT chng_when,
commentcol FROM
audit_log; 
Cascading Triggers

Cascading Trigger Demo


CREATE TABLE cascade (
testcol VARCHAR2(10));

CREATE OR REPLACE
TRIGGER t_cascade
AFTER INSERT
ON cascade

BEGIN
  INSERT INTO cascade
  (testcol)
  VALUES
  ('change'); 
END t_cascade;
/

INSERT INTO cascade


(testcol) VALUES ('ABC'); 
Mutating Triggers

Mutating Trigger Demo

The insert into t1 firest the trigger which attempts to count the number of records in t1 ... which is
ambiguous.
CREATE TABLE t1 (x int); CREATE OR REPLACE TRIGGER t_trigger
CREATE TABLE t2 (x int); AFTER INSERT ON t1 FOR EACH ROW

INSERT INTO t1 VALUES DECLARE


(1);   PRAGMA AUTONOMOUS_TRANSACTION;
 i PLS_INTEGER; 
SELECT * FROM t1; BEGIN
7
SELECT * FROM t2;

CREATE OR REPLACE
TRIGGER t_trigger
AFTER INSERT
ON t1
FOR EACH ROW

DECLARE
 i PLS_INTEGER;
BEGIN   SELECT COUNT(*)
  SELECT COUNT(*)   INTO i
  INTO i   FROM t1;
  FROM t1;
  INSERT INTO t2
  INSERT INTO t2   VALUES
  VALUES   (i);
  (i);   COMMIT;
END; END;
/ /

INSERT INTO t1 VALUES INSERT INTO t1 VALUES (1);


(1);
SELECT COUNT(*) FROM t1;
SELECT COUNT(*) FROM SELECT COUNT(*) FROM t2;
t1;
SELECT COUNT(*) FROM
t2;
Mutating Trigger Fix With
Autonomous Transaction

Count on t1 is performed
as though a different user
logged on and asked the
question of t1.
 
Trigger Enforcing Auditing

Auditing With A Statement Trigger


CREATE TABLE changes (
fnew       VARCHAR2(10),
fold       VARCHAR2(10),
changed_by
VARCHAR2(30) DEFAULT
USER);

CREATE OR REPLACE
TRIGGER t_t2_audit
AFTER UPDATE 
ON t2 
REFERENCING NEW AS n
OLD AS o
FOR EACH ROW

BEGIN
  INSERT INTO changes
  VALUES (:n.x, :o.x,
user); 
END t_t2_audit;
/

SELECT * FROM t2;

8
UPDATE t2
SET x = 1;
COMMIT;

SELECT * FROM
changes; 
Trigger Enforcing Integrity Constraint

Trigger To Disallow Entry Of Future Dates


CREATE OR REPLACE
TRIGGER t_date 
BEFORE INSERT 
ON orders 
FOR EACH ROW

DECLARE
 bad_date EXCEPTION;
BEGIN
  IF :new.datecol >
SYSDATE THEN
   
RAISE_APPLICATION_ER
ROR(-20005,'Future
Dates Not Allowed');
  END IF;
END;
/

INSERT INTO orders


VALUES ('ABC', 999,
SYSDATE-1);
INSERT INTO orders
VALUES ('ABC', 999,
SYSDATE);
INSERT INTO orders
VALUES ('ABC', 999,
SYSDATE+1); 
Trigger Ensuring Data Entry During Business Hours

Trigger To Disallow Entry Of Future Dates


CREATE OR REPLACE
PROCEDURE secure_dml(
dateval IN DATE)IS
BEGIN
  IF TO_CHAR (dateval,
'HH24:MI') NOT
BETWEEN '08:00' AND
'18:00'
  OR TO_CHAR (dateval,
'DY') IN ('SAT', 'SUN')
THEN
   
RAISE_APPLICATION_ER
ROR (-20205, 'Changes
only allowed during office
hours');
  END IF;
END secure_dml;
/

CREATE OR REPLACE
9
TRIGGER secure_data
BEFORE INSERT OR
UPDATE OR DELETE
ON orders
FOR EACH ROW
BEGIN
  secure_dml(:NEW.datec
ol);
END;
/

INSERT INTO orders


VALUES ('ABC', 999,
SYSDATE-1);
INSERT INTO orders
VALUES ('ABC', 999,
SYSDATE-4/24);
INSERT INTO orders
VALUES ('ABC', 999,
SYSDATE+1);
 

10

Das könnte Ihnen auch gefallen