You are on page 1of 14

Triggers are procedures that are stored in the database and implicitly run, or fired, when something

happens.

The events that fire a trigger include the following: DML statements that modify data in a table (INSERT, UPDATE, or DELETE) DDL statements System events such as startup, shutdown, and error messages User events such as logon and logoff When you create a trigger, Oracle enables it automatically. You can subsequently disable and enable a trigger with the DISABLE and ENABLE clause of the ALTER TRIGGER or ALTER TABLE statement.
CREATE OR REPLACE TRIGGER <trigger_name> [<ENABLE | DISABLE>] <BEFORE | AFTER> <ACTION> [OR <ACTION> OR <ACTION>] ON <table_name> [FOLLOWS <schema.trigger_name>] DECLARE <variable definitions> BEGIN <trigger_code> EXCEPTION <exception clauses> END <trigger_name>; /

You can use triggers in a number of ways to customize information management in an Oracle database. For example, triggers are commonly used to: Provide sophisticated auditing Prevent invalid transactions Enforce referential integrity Enforce complex business rules Enforce complex security authorizations Provide transparent event logging Automatically generate derived column values Enable building complex views that are updatable Track system events 1

Types of Triggers
1. 2. 3. 4. Row Triggers and Statement Triggers BEFORE and AFTER Triggers INSTEAD OF Triggers Triggers on System Events and User Events

Row Triggers A row trigger is fired each time the table is affected by the triggering statement. For example, if an UPDATE statement updates multiple rows of a table, a row trigger is fired once for each row affected by the UPDATE statement. If a triggering statement affects no rows, a row trigger is not run. Row triggers are useful if the code in the trigger action depends on data provided by the triggering statement or rows that are affected. Statement Triggers A statement trigger is fired once on behalf of the triggering statement, regardless of the number of rows in the table that the triggering statement affects, even if no rows are affected. For example, if a DELETE statement deletes several rows from a table, a statement-level DELETE trigger is fired only once. Statement triggers are useful if the code in the trigger action does not depend on the data provided by the triggering statement or the rows affected. BEFORE Triggers BEFORE triggers run the trigger action before the triggering statement is run. This type of trigger is commonly used in the following situations: When the trigger action determines whether the triggering statement should be allowed to complete. Using a BEFORE trigger for this purpose, you can eliminate unnecessary processing of the triggering statement and its eventual rollback in cases where an exception is raised in the trigger action. To derive specific column values before completing a triggering INSERT or UPDATE statement. AFTER Triggers AFTER triggers run the trigger action after the triggering statement is run. INSTEAD OF Triggers INSTEAD OF triggers provide a transparent way of modifying views that cannot be modified directly through DML statements (INSERT, UPDATE, and DELETE). These triggers are called INSTEAD OF triggers because, unlike other types of triggers, Oracle fires the trigger instead of executing the triggering statement. You can write normal INSERT, UPDATE, and DELETE statements against the view and the INSTEAD OF trigger is fired to update the underlying tables appropriately. INSTEAD OF triggers are activated for each row of the view that gets modified.

Create Statement Level Triggers (the default) Statement Level Trigger With A Single Action CREATE OR REPLACE TRIGGER <trigger_name> [<ENABLE | DISABLE>] <BEFORE | AFTER> <ACTION> [OR <ACTION> OR <ACTION>] ON <table_name> DECLARE <variable definitions> BEGIN <trigger_code> EXCEPTION <exception clauses> END <trigger_name>; /

CREATE TABLE orders ( somecolumn VARCHAR2(20), numbercol NUMBER(10), datecol DATE);

CREATE OR REPLACE TRIGGER statement_level BEFORE UPDATE ON orders DECLARE vMsg VARCHAR2(30) := 'Statement Level Trigger Fired'; BEGIN dbms_output.put_line(vMsg); END statement_level; / set serveroutput on INSERT INTO orders (somecolumn) VALUES ('ABC'); UPDATE orders SET somecolumn = 'XYZ';

Statement Level Trigger With Multiple Actions 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'); 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 TRIGGER <trigger_name> [FOLLOWS <schema.trigger_name>] [<ENABLE | DISABLE>] <BEFORE | AFTER> <ACTION> OR <ACTION> OR <ACTION> [OF <column_name_list>] ON <table_name> REFERENCING NEW AS <synonym> OLD AS <synonym> PARENT AS <synonym> FOR EACH ROW DECLARE <variable definitions> BEGIN <trigger_code> EXCEPTION <exception clauses> END <trigger_name>; /

CREATE TABLE t ( rid NUMBER(5), col VARCHAR2(3)); ALTER TABLE t ADD CONSTRAINT pk_t PRIMARY KEY (rid) USING INDEX; CREATE SEQUENCE seq_t; CREATE OR REPLACE TRIGGER row_level BEFORE INSERT ON t FOR EACH ROW BEGIN SELECT seq_t.NEXTVAL INTO :NEW.rid FROM DUAL; dbms_output.put_line(:NEW.rid); END row_level; / INSERT INTO t (col) VALUES ('A'); INSERT INTO t (col) VALUES ('B'); INSERT INTO t (col) VALUES ('C'); SELECT * FROM t; Row Level Trigger With A Single Action 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'); INSERT INTO orders (somecolumn) VALUES ('ABC'); SELECT * FROM orders; UPDATE orders SET somecolumn = 'XYZ';

Row Level Trigger With Multiple Actions 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; Row Level Trigger With OF Clause 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;

Row Level Trigger With Referencing Clause 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); 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;

Before Insert CREATE TABLE orders ( order_id number(5), quantity number(4), cost_per_item number(6,2), total_cost number(8,2), create_date date, created_by varchar2(10) ); We could then create a BEFORE INSERT trigger as follows: CREATE OR REPLACE TRIGGER orders_before_insert BEFORE INSERT ON orders FOR EACH ROW DECLARE v_username varchar2(10); BEGIN -- Find username of person performing INSERT into table SELECT user INTO v_username FROM dual; -- Update create_date field to current system date :new.create_date := sysdate; -- Update created_by field to the username of the person performing the INSERT :new.created_by := v_username; END; /

After Trigger CREATE TABLE orders ( order_id number(5), quantity number(4), cost_per_item number(6,2), total_cost number(8,2) ); We could then create an AFTER INSERT trigger as follows: CREATE OR REPLACE TRIGGER orders_after_insert AFTER INSERT ON orders FOR EACH ROW DECLARE v_username varchar2(10); BEGIN -- Find username of person performing the INSERT into the table SELECT user INTO v_username FROM dual; -- Insert record into audit table INSERT INTO orders_audit ( order_id, quantity, cost_per_item, total_cost, username ) VALUES ( :new.order_id, :new.quantity, :new.cost_per_item, :new.total_cost, v_username ); END; /

Before Update CREATE TABLE orders ( order_id number(5), quantity number(4), cost_per_item number(6,2), total_cost number(8,2), updated_date date, updated_by varchar2(10) ); We could then create a BEFORE UPDATE trigger as follows: CREATE OR REPLACE TRIGGER orders_before_update BEFORE UPDATE ON orders FOR EACH ROW DECLARE v_username varchar2(10); BEGIN -- Find username of person performing UPDATE on the table SELECT user INTO v_username FROM dual; -- Update updated_date field to current system date :new.updated_date := sysdate; -- Update updated_by field to the username of the person performing the UPDATE :new.updated_by := v_username; END; /

10

create or replace trigger emp_biu BEFORE INSERT OR UPDATE of salary on employee for each row declare v_error VARCHAR2(2000); begin if :new.salary > 10000 then v_error:=:old.first_name||' cannot have that much!'; raise_application_error(-20999,v_error); end if; end; /

SQL> CREATE OR REPLACE TRIGGER emp_dept_del 2 AFTER DELETE ON employee 3 FOR EACH ROW 4 BEGIN 5 DBMS_OUTPUT.PUT_LINE (':OLD.id' || :OLD.id); 6 7 8 END; 9 / Trigger created. SQL> SQL> delete from employee; :OLD.id01 :OLD.id02 :OLD.id03 :OLD.id04 :OLD.id05 :OLD.id06 :OLD.id07 :OLD.id08 8 rows deleted.

11

create table myaudit( 2 id VARCHAR2(4 BYTE) NOT NULL, 3 old_value VARCHAR2(40 BYTE), 4 new_value VARCHAR2(40 BYTE) 5 ); SQL> CREATE OR REPLACE TRIGGER before_employee_salary_update 2 BEFORE UPDATE OF salary 3 ON employee 4 FOR EACH ROW WHEN (new.salary < old.salary * 0.75) 5 BEGIN 6 dbms_output.put_line('id = ' || :old.id); 7 dbms_output.put_line('Old salary = ' || :old.salary); 8 dbms_output.put_line('New salary = ' || :new.salary); 9 dbms_output.put_line('The salary reduction is more than 25%'); 10 11 INSERT INTO Myaudit ( 12 id, old_value, new_value 13 ) VALUES ( 14 :old.id, :old.salary, :new.salary 15 ); 16 END before_employee_salary_update; 17 / Trigger created. Update the salary CREATE OR REPLACE TRIGGER LogRSChanges 2 BEFORE INSERT OR DELETE OR UPDATE ON employee 3 FOR EACH ROW 4 DECLARE 5 v_ChangeType CHAR(1); 6 BEGIN 7 /* Use 'I' for an INSERT, 'D' for DELETE, and 'U' for UPDATE. */ 8 IF INSERTING THEN 9 v_ChangeType := 'I'; 10 ELSIF UPDATING THEN 11 v_ChangeType := 'U'; 12 ELSE 13 v_ChangeType := 'D'; 14 END IF; 15 16 DBMS_OUTPUT.put_line(v_ChangeType ||' '|| USER ||' ' ||SYSDATE); 17 END LogRSChanges; 18 /

12

CREATE TRIGGER employee_bir 2 BEFORE INSERT ON employee 3 FOR EACH ROW 4 begin 5 if upper(:new.name) = 'J' then 6 raise_application_error(20000, 'Sorry, that genius is not allowed.'); 7 end if; 8 end; 9 / SELECT trigger_name, status FROM user_triggers;

13

CREATE or REPLACE TRIGGER trg1 BEFORE INSERT ON emp1 for each row BEGIN :new.ename := upper(:new.ename); END; / Delete Trigger in Restiction Delete Trigger Code: CREATE or REPLACE TRIGGER trg1 AFTER DELETE ON emp1 for each row BEGIN IF :old.eno = 1 THEN raise_application_error(-20015, 'Not Delete this Row'); END IF; END; / Delete Trigger Result: SQL>delete from emp1 where eno = 1; Error Code: 20015 Error Name: Not Delete this Row

14

You might also like