Академический Документы
Профессиональный Документы
Культура Документы
PL/SQL - Triggers
Triggers are stored programs, which are automatically executed or fired
when some events occur. Triggers are, in fact, written to be executed in
response to any of the following events:
A database manipulation (DML) statement (DELETE, INSERT, or
UPDATE).
A database definition (DDL) statement (CREATE, ALTER, or DROP).
A database operation (SERVERERROR, LOGON, LOGOFF, STARTUP, or
SHUTDOWN).
Triggers could be defined on the table, view, schema, or database with
which the event is associated.
Benefits of Triggers
Triggers can be written for the following purposes:
Generating some derived column values automatically
Enforcing referential integrity
Event logging and storing information on table access
Auditing
Synchronous replication of tables
Imposing security authorizations
Preventing invalid transactions
Creating Triggers
CREATE [OR REPLACE ] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF }
{INSERT [OR] | UPDATE [OR] | DELETE}
[OF col_name]
ON table_name
[REFERENCING OLD AS o NEW AS n]
[FOR EACH ROW]
WHEN (condition)
DECLARE
Declaration-statements
BEGIN
Executable-statements
EXCEPTION
Exception-handling-statements
END;
Creating Triggers
Where,
CREATE [OR REPLACE] TRIGGER trigger_name: Creates or replaces an existing trigger with the trigger_name.
{BEFORE | AFTER | INSTEAD OF} : This specifies when the trigger would be executed. The INSTEAD OF clause is
used for creating trigger on a view.
{INSERT [OR] | UPDATE [OR] | DELETE}: This specifies the DML operation.
[OF col_name]: This specifies the column name that would be updated.
[ON table_name]: This specifies the name of the table associated with the trigger.
[REFERENCING OLD AS o NEW AS n]: This allows you to refer new and old values for various DML statements, like
INSERT, UPDATE, and DELETE.
[FOR EACH ROW]: This specifies a row level trigger, i.e., the trigger would be executed for each row being affected.
Otherwise the trigger will execute just once when the SQL statement is executed, which is called a table level
trigger.
WHEN (condition): This provides a condition for rows for which the trigger would fire. This clause is valid only for
row level triggers.
Example
The following program creates a row level trigger for the customers table that would fire for INSERT or
UPDATE or DELETE operations performed on the CUSTOMERS table. This trigger will display the salary
difference between the old values and new values:
CREATE OR REPLACE TRIGGER display_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END;
/
CREATE OR REPLACE TRIGGER Salary_check
BEFORE INSERT OR UPDATE OF Sal, Job ON Emp99
FOR EACH ROW
DECLARE
Minsal NUMBER;
Maxsal NUMBER;
Salary_out_of_range EXCEPTION;
BEGIN
SELECT Minsal, Maxsal INTO Minsal, Maxsal FROM Salgrade
WHERE Job_classification = :new.Job;
IF (:new.Sal < Minsal OR :new.Sal > Maxsal) THEN
RAISE Salary_out_of_range;
END IF;
EXCEPTION
WHEN Salary_out_of_range THEN
Raise_application_error (-20300,
'Salary '||TO_CHAR(:new.Sal)||' out of range for '
||'job classification '||:new.Job ||' for employee '||:new.Ename);
WHEN NO_DATA_FOUND THEN
Raise_application_error(-20322,
'Invalid Job Classification ||:new.Job_classification);
END;
Considerations
Here following two points are important and should be noted carefully:
OLD and NEW references are not available for table level triggers,
rather you can use them for record level triggers.
If you want to query the table in the same trigger, then you should use
the AFTER keyword, because triggers can query the table or change it
again only after the initial changes are applied and the table is back in a
consistent state.
Above trigger has been written in such a way that it will fire before any
DELETE or INSERT or UPDATE operation on the table, but you can write
your trigger on a single or multiple operations, for example BEFORE
DELETE, which will fire whenever a record will be deleted using DELETE
operation on the table.
Statement and Row Triggers
Example 1: Monitoring Statement Events
SQL> INSERT INTO dept (deptno, dname, loc)
2 VALUES (50, 'EDUCATION', 'NEW YORK');
BEGIN
CREATE OR REPLACE VIEW SELECT COUNT(*) INTO rowcnt FROM Emp_tab WHERE empno = :n.empno;
manager_info AS IF rowcnt = 0 THEN
INSERT INTO Emp_tab (empno,ename) VALUES (:n.empno, :n.ename);
ELSE
SELECT e.ename, e.empno, UPDATE Emp_tab SET Emp_tab.ename = :n.ename
d.dept_type, d.deptno, WHERE Emp_tab.empno = :n.empno;
p.prj_level, p.projno END IF;
SELECT COUNT(*) INTO rowcnt FROM Dept_tab WHERE deptno = :n.deptno;
FROM Emp_tab e, Dept_tab d, IF rowcnt = 0 THEN
Project_tab p INSERT INTO Dept_tab (deptno, dept_type)
VALUES(:n.deptno, :n.dept_type);
WHERE e.empno = d.mgr_no AND ELSE
d.deptno = p.resp_dept; UPDATE Dept_tab SET Dept_tab.dept_type = :n.dept_type
WHERE Dept_tab.deptno = :n.deptno;
END IF;
SELECT COUNT(*) INTO rowcnt FROM Project_tab
WHERE Project_tab.projno = :n.projno;
IF rowcnt = 0 THEN
INSERT INTO Project_tab (projno, prj_level)
VALUES(:n.projno, :n.prj_level);
ELSE
UPDATE Project_tab SET Project_tab.prj_level = :n.prj_level
WHERE Project_tab.projno = :n.projno;
END IF;
END;
Triggers on System Events and User
Events
You can use triggers to publish information about database events to subscribers.
Applications can subscribe to database events just as they subscribe to messages from other
applications. These database events can include:
System events
Database startup and shutdown
Data Guard role transitions
Server error message events
User events
User logon and logoff
DDL statements (CREATE, ALTER, and DROP)
DML statements (INSERT, DELETE, and UPDATE)
Triggers on system events can be defined at the database level or schema level. A trigger
defined at the database level fires for all users, and a trigger defined at the schema or table
level fires only when the triggering event involves that schema or table
System Events
System events that can fire triggers are related to instance startup and shutdown and error
messages. Triggers created on startup and shutdown events have to be associated with the
database. Triggers created on error events can be associated with the database or with a
schema.
STARTUP triggers fire when the database is opened by an instance. Their attributes include
the system event, instance number, and database name.
SHUTDOWN triggers fire just before the server starts shutting down an instance. You can
use these triggers to make subscribing applications shut down completely when the
database shuts down. For abnormal instance shutdown, these triggers cannot be fired. The
attributes of SHUTDOWN triggers include the system event, instance number, and database
name.
SERVERERROR triggers fire when a specified error occurs, or when any error occurs if no
error number is specified. Their attributes include the system event and error number.
DB_ROLE_CHANGE triggers fire when a role transition (failover or switchover) occurs in a
Data Guard configuration. The trigger notifies users when a role transition occurs, so that
client connections can be processed on the new primary database and applications can
continue to run.
User Events
User events that can fire triggers are related to user logon and logoff, DDL statements,
and DML statements.
LOGON and LOGOFF triggers can be associated with the database or with a schema.
Their attributes include the system event and user name, and they can specify simple
conditions on USERID and USERNAME.
LOGON triggers fire after a successful logon of a user.
LOGOFF triggers fire at the start of a user logoff.
System Triggers
CREATE OR REPLACE TRIGGER my_trigger
AFTER CREATE ON DATABASE
BEGIN
Do_Something;
END;
ERROR at line 1:
ORA-04091: table CGMA2.EMP is mutating, trigger/function may not see it
Example: Mutating Table (fixed)
CREATE OR REPLACE TRIGGER emp_count
AFTER DELETE ON emp
-- FOR EACH ROW
DECLARE
num INTEGER;
BEGIN
SELECT COUNT(*) INTO num FROM emp;
DBMS_OUTPUT.PUT_LINE(' There are now ' || num || ' employees.');
END;
/
6 rows deleted.
Rules for Good Practice
Rule 1: Do not change data in the primary key, foreign key, or
unique key columns of any table
Rule 2: Do not update records in the same table you read during
the same transaction
Rule 3: Do not aggregate over the same table you are updating
Rule 4: Do not read data from a table which is updated during
the same transaction
Rule 5: Do not use SQL DCL (Data Control Language) statements
in triggers