Triggers in PL/SQL
In the context of PL/SQL (Procedural Language/Structured Query Language), triggers are a type of stored procedure that automatically execute (or "fire") when a specified event occurs. Triggers can be used to enforce business rules, maintain audit trails, and synchronize tables.
Types of Triggers
- Row-level triggers: These are executed for each row affected by the triggering event.
- Statement-level triggers: These are executed once for the entire triggering event.
Trigger Timing
Triggers can be set to fire:
Basic Syntax
- Before the triggering event.
- After the triggering event.
- Instead of the triggering event (mostly used in views).
Basic Syntax
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF} triggering_event
ON table_name
[FOR EACH ROW]
DECLARE
-- variable declarations
BEGIN
-- trigger logic
END;
Example 1: Row-Level Trigger
Suppose you have an employees table, and you want to log changes to the salary column.
Create the logging table:
CREATE TABLE salary_log (
emp_id NUMBER,
old_salary NUMBER,
new_salary NUMBER,
change_date DATE
);
Create the trigger:
CREATE OR REPLACE TRIGGER salary_change_triggerAFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
INSERT INTO salary_log (emp_id, old_salary, new_salary, change_date)
VALUES (:OLD.emp_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
- :OLD refers to the old value before the update.
- :NEW refers to the new value after the update.
Suppose you want to track when the employees table is modified.
Create the audit table:
CREATE TABLE audit_log (
table_name VARCHAR2(50),
action VARCHAR2(50),
action_date DATE
);
Create the trigger
CREATE OR REPLACE TRIGGER employees_audit_trigger
AFTER INSERT OR UPDATE OR DELETE ON employees
BEGIN
INSERT INTO audit_log (table_name, action, action_date)
VALUES ('employees', 'DML operation', SYSDATE);
END;
Example 3: Before Insert Trigger
You want to ensure that a value is always uppercase before inserting it into a table.
Create the table:
CREATE TABLE departments (
dept_id NUMBER,
dept_name VARCHAR2(50)
);
Create the trigger:
CREATE OR REPLACE TRIGGER dept_name_uppercase_trigger
BEFORE INSERT ON departments
FOR EACH ROW
BEGIN
:NEW.dept_name := UPPER(:NEW.dept_name);
END;
In this example, :NEW.dept_name is converted to uppercase before the row is inserted into the departments table.
Best Practices
- Use row-level triggers for operations that need to check or modify each row's values.
- Use statement-level triggers for operations that need to enforce rules at the table level.
- Keep triggers simple to avoid complex interdependencies and performance issues.
- Use triggers judiciously to maintain database integrity and ensure that business rules are consistently applied.
Triggers are powerful tools in PL/SQL for managing and maintaining data integrity, and understanding how to create and use them effectively can greatly enhance your database management capabilities.
Real Time Example:
We will create an
employees
table and a trigger that logs changes to the salary
column into a salary_log
table.-- Create employees table
CREATE TABLE employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(100),
salary NUMBER
);
-- Create salary_log table
CREATE TABLE salary_log (
log_id NUMBER PRIMARY KEY,
emp_id NUMBER,
old_salary NUMBER,
new_salary NUMBER,
change_date DATE,
CONSTRAINT fk_emp FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
-- Create sequence for salary_log table
CREATE SEQUENCE salary_log_seq
START WITH 1
INCREMENT BY 1;
-- Create the trigger
CREATE OR REPLACE TRIGGER salary_change_trigger
AFTER UPDATE OF salary ON employees
FOR EACH ROW
DECLARE
log_id_seq NUMBER;
BEGIN
-- Generate a unique log_id for the salary_log table
SELECT salary_log_seq.NEXTVAL INTO log_id_seq FROM dual;
INSERT INTO salary_log (log_id, emp_id, old_salary, new_salary, change_date)
VALUES (log_id_seq, :OLD.emp_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
/
-- Insert an employee
INSERT INTO employees (emp_id, emp_name, salary) VALUES (1, 'John Doe', 50000);
-- Update the employee's salary
UPDATE employees SET salary = 55000 WHERE emp_id = 1;
-- Check the salary_log table
SELECT * FROM salary_log;
Example:Let's create a complete example of a statement-level trigger. We'll use an
orders
table and create a statement-level trigger to log any insert, update, or delete operations performed on this table. The logs will be stored in an audit_log
table.-- Create orders table
CREATE TABLE orders (
order_id NUMBER PRIMARY KEY,
customer_id NUMBER,
order_date DATE,
total_amount NUMBER
);
-- Create audit_log table
CREATE TABLE audit_log (
log_id NUMBER PRIMARY KEY,
table_name VARCHAR2(50),
operation VARCHAR2(50),
operation_date DATE
);
-- Create sequence for audit_log table
CREATE SEQUENCE audit_log_seq
START WITH 1
INCREMENT BY 1;
-- Create the trigger
CREATE OR REPLACE TRIGGER orders_audit_trigger
AFTER INSERT OR UPDATE OR DELETE ON orders
DECLARE
log_id_seq NUMBER;
BEGIN
-- Generate a unique log_id for the audit_log table
SELECT audit_log_seq.NEXTVAL INTO log_id_seq FROM dual;
INSERT INTO audit_log (log_id, table_name, operation, operation_date)
VALUES (log_id_seq, 'orders', CASE
WHEN INSERTING THEN 'INSERT'
WHEN UPDATING THEN 'UPDATE'
WHEN DELETING THEN 'DELETE'
END, SYSDATE);
END;
/
-- Insert an order
INSERT INTO orders (order_id, customer_id, order_date, total_amount) VALUES (1, 101, SYSDATE, 1500);
-- Update the order
UPDATE orders SET total_amount = 1600 WHERE order_id = 1;
-- Delete the order
DELETE FROM orders WHERE order_id = 1;
-- Check the audit_log table
SELECT * FROM audit_log;
Example:This example demonstrates how to create a trigger that ensures a column value is always stored in uppercase before inserting or updating a row in the table.
-- Create departments table
CREATE TABLE departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(50)
);
-- Create the trigger
CREATE OR REPLACE TRIGGER dept_name_uppercase_trigger
BEFORE INSERT OR UPDATE ON departments
FOR EACH ROW
BEGIN
:NEW.dept_name := UPPER(:NEW.dept_name);
END;
/
-- Insert a department with a lowercase name
INSERT INTO departments (dept_id, dept_name) VALUES (1, 'marketing');
-- Update the department name to lowercase
UPDATE departments SET dept_name = 'finance' WHERE dept_id = 1;
-- Check the departments table
SELECT * FROM departments;
Comments
Post a Comment