Lecture - 08 PLSQL Triggers and Audit Mechanisms
Lecture - 08 PLSQL Triggers and Audit Mechanisms
Instructor:
▪ Eric Maniraguha | eric.maniraguha@auca.ac.rw | LinkedIn Profile
6h00 pm – 9h50 pm
▪ Monday A -G207
▪ Tuesday B-G204
▪ Wednesday E-106 April 2025
▪ Thursday F-G307 1
Database development with PL/SQL
Reference reading
▪ Difference between Cursor and Trigger in DBMS
▪ Difference between Cursor and Trigger in PLSQL
▪ 9 Using Triggers
▪ CREATE TRIGGER
▪ Oracle PL/SQL Trigger: A Comprehensive Guide
▪ Auditing employee table changes with PL/SQL Trigger
▪ Oracle PL/SQL
A trigger in PL/SQL is a predefined program or block of code that is automatically executed (or "fired") when a specific event occurs in the database. It is stored in the database and
is triggered by actions such as INSERT, UPDATE, DELETE, or DDL operations on a table, view, schema, or database.
▪Automatic Execution: Triggers execute automatically when the specified event occurs.
▪Data Integrity: They help enforce business rules and maintain consistency in the database.
▪Error Handling: Triggers can validate data before changes are made.
▪Event-driven: They respond to specific actions like INSERT, UPDATE, DELETE, or system events like LOGON, SHUTDOWN.
3
Oracle – PLSQL Database Triggers
1. In Oracle PL/SQL, a trigger is a named block of PL/SQL code that is automatically executed (or "fired") in response to specific events on a particular table, view,
schema, or database. Triggers can enforce business rules, maintain audit trails, or perform automated actions.
2. A Trigger is a PL/SQL block that executes implicitly in response to a specific database event (e.g., INSERT,
UPDATE, DELETE) on a table or view. It is planned for a particular event (such as data changes) and timing
(e.g., BEFORE or AFTER the event).
Characteristics:
▪Executed Implicitly: Trigger fires automatically when the specified event occurs.
▪Event-Driven: Associated with DML operations (e.g., INSERT, UPDATE, DELETE).
▪Centralized Actions: Performs centralized and related actions to enforce data integrity, auditing,
or automation.
▪Complexity: Excessive use of triggers can lead to complex interdependencies between database
objects.
▪Auditing: Automatically log details of changes (e.g., who modified data, when, and what
changed) into a separate audit table.
▪Data Validation: Ensure specific business rules (e.g., salary cannot exceed a certain threshold)
are enforced before inserting or updating a row.
▪Cascading Updates: Update related tables to maintain data integrity when changes are made. Source Image: https://csveda.com/pl-sql-trigger-basics-uses/
Triggers are a powerful feature in relational databases like Oracle, MySQL, or PostgreSQL, allowing automation and ensuring consistency
within the database. However, overuse can lead to performance overhead, so they should be employed carefully.
4
PL/SQL Triggers – Advantages
5
Disadvantage Description Impact
Can slow down database performance,
Performance Triggers add processing time to INSERT,
especially for high-traffic tables or large
Overhead UPDATE, or DELETE operations.
datasets.
Debugging and Triggers execute implicitly, making them Difficult for developers to track issues or
Maintenance hard to debug and trace. understand the flow of data modifications.
PL/SQL Triggers –
Causes confusion and reduces
Business logic in triggers is not
Hidden Logic transparency, leading to unexpected
immediately visible in application code.
behavior.
Disadvantages Increased
Complexity
Triggers can cause unintended cascading
effects (e.g., one trigger firing another).
Creates complex dependencies, making the
database harder to manage.
6
Triggers Classification: Application & Database Trigger
Types:
▪ UI Event Handlers: Trigger actions when a user interacts with the interface (e.g., button clicks).
▪ Business Logic Triggers: Trigger specific actions or calculations based on certain conditions.
▪ Database Interactions: Trigger actions after database operations (e.g., after a record is updated).
▪ Use Cases: Business rule enforcement, user interaction handling, database operation responses.
7
Trigger Syntax, Behavior of Database Triggers
-- Defines the table or view the trigger applies to. Trigger Event:
ON table_name Specifies what DML
operation triggers
-- References old and new row values for processing (optional). the execution of the
[REFERENCING OLD AS o NEW AS n] trigger. This can be:
-- Executes the trigger for each affected row (optional).
[FOR EACH ROW]
▪INSERT Trigger Timing:
-- Executes the trigger conditionally if the specified condition is true. ▪UPDATE Specifies when the trigger fires
WHEN (condition) ▪DELETE in relation to the triggering
event. This can be:
BEGIN
-- Define the logic executed when the trigger fires. ▪BEFORE: Trigger fires before the
NULL; -- Replace with actual trigger logic. operation is executed.
EXCEPTION ▪AFTER: Trigger fires after the operation
-- Define logic for handling errors during trigger. execution. is executed.
NULL; -- Replace with actual error handling logic ▪INSTEAD OF: Trigger replaces the
END;
triggering event (used primarily for
/
views).
8
Where,
CREATE [OR REPLACE] TRIGGER trigger_name − Creates or replaces an existing trigger with When to Use Triggers
the trigger_name.
1. DML Triggers:
Use DML Triggers to automate actions in response to changes in data.
{BEFORE | AFTER | INSTEAD OF} − This specifies when the trigger will be executed. The INSTEAD These are ideal for:
OF clause is used for creating trigger on a view. ▪ Logging changes to tables (e.g., tracking updates or deletions).
▪ Enforcing business rules and integrity constraints automatically when
INSERT, UPDATE, or DELETE operations occur.
{INSERT [OR] | UPDATE [OR] | DELETE} − This specifies the DML operation.
2. INSTEAD OF Triggers:
Use INSTEAD OF Triggers to enable INSERT, UPDATE, or DELETE
operations on views that are otherwise non-updatable. These triggers
[OF col_name] − This specifies the column name that will be updated. allow you to define custom logic for handling DML operations on such
views.
3. DDL Triggers:
[ON table_name] − This specifies the name of the table associated with the trigger. Use DDL Triggers to monitor or control schema-level changes. These
triggers are helpful for:
▪ Auditing schema modifications (e.g., DROP, ALTER, or CREATE
[REFERENCING OLD AS o NEW AS n] − This allows you to refer new and old values for various DML operations).
statements, such as INSERT, UPDATE, and DELETE. ▪ Restricting unauthorized schema changes at the database or schema
level.
[FOR EACH ROW] − This specifies a row-level trigger, i.e., the trigger will 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. Caution with Triggers
▪ Avoid excessive use of triggers to prevent complex interdependencies.
▪ Excessive use can degrade performance and make debugging difficult.
WHEN (condition) − This provides a condition for rows for which the trigger would fire. This clause is ▪ Disable or drop triggers temporarily when troubleshooting or performing
valid only for row-level triggers.
bulk operations.
9
Types of Database Triggers
▪Description: Activated by ▪Description: Fired by events like ▪Description: Responds to internal ▪Description: Replaces the default ▪Description: Combines multiple
INSERT, UPDATE, or DELETE CREATE, ALTER, or DROP that database events (e.g., action of a triggering event with timing points (before and after) in
operations. change database structures. logon/logoff, startup/shutdown). custom logic. one trigger, allowing row-level and
▪Use Case: Enforces business rules ▪Use Case: Audits schema changes ▪Use Case: Monitors system ▪Use Case: Useful for views to statement-level logic.
and maintains audit trails. and enforces security policies. activity and enforces security. handle updates or inserts. ▪Use Case: Organizes complex
logic in Oracle databases and
avoids conflicts between multiple
triggers.
Summary
These triggers help automate actions, enforce rules, and maintain data integrity in database operations.
10
Row-Level Trigger
A row-level trigger is a type of trigger that is fired for each row affected by a Data Manipulation Language (DML) operation such as INSERT, UPDATE, or DELETE. It executes once for
each row that is modified, and it allows you to perform actions based on the data in the individual rows before or after the operation.
Row-level triggers are defined using the FOR EACH ROW clause, and they have access to the :NEW and :OLD pseudorecords, which store the values of the columns in the affected
rows.
11
BEFORE vs AFTER: What’s the difference in this context?
When it fires Just before the row is updated Just after the row is updated
Can access :NEW? Yes and can modify it Yes (read-only; cannot modify :NEW)
Use case Validation, transformation, custom logic Auditing, logging, sending notifications
12
Example of a Row-Level Trigger: Logging Salary Changes
In this example, we will create a row-level trigger that logs every salary change to an audit table.
By using row-level triggers effectively, you can ensure that your database enforces business
rules and data integrity in a transparent and automated way. However, it's important to
balance their use with performance considerations.
13
Row-Level Trigger
Row-Level Trigger –
LAST_NAME,
OLD_SALARY,
NEW_SALARY,
Optimized
SAL_DIFF,
CHANGED_AT
)
VALUES (
:NEW.EMPLOYEE_ID,
:NEW.LAST_NAME,
:OLD.SALARY,
Output
:NEW.SALARY,
:NEW.SALARY - :OLD.SALARY,
SYSDATE
);
END;
/
15
Table Auditing using DML Triggers in Oracle PL/SQL
Performance Impact Can affect application performance Minimal impact with optimized configurations
Ease of Implementation Requires coding and testing for each trigger Requires configuration but no coding
Tamper Resistance Can be bypassed by disabling triggers Logs are secured and tamper-proof
Cost No additional cost beyond database licensing Often part of enterprise solutions with extra fees
Regulatory Compliance Limited (manual efforts required) Designed for compliance with built-in tools
16
I. Scenario Question: Banking Context DDL Trigger
Scenario-Based Question
In a bank's database system, schema-level changes such as creating or altering tables for customer records, transaction logs, or account details must be strictly monitored
for compliance and security purposes. You are tasked with implementing a mechanism to track and log all DDL (Data Definition Language) operations like CREATE,
ALTER, and DROP. This ensures that unauthorized or accidental modifications to critical database structures are detected and auditable.
Objectives:
17
Solution DDL Trigger: Banque Scenario
Step 1: Create the Audit Table Validate: Query the audit log: Test Case 2: Altering a Table
The audit table will store details of all CREATE, ALTER, and DROP operations. Execute the following command:
SELECT * FROM audit_ddl_log;
CREATE TABLE audit_ddl_log ( ALTER TABLE customer_feedback ADD feedback_date DATE;
id NUMBER GENERATED BY DEFAULT AS IDENTITY,
event_type VARCHAR2(50),
object_name VARCHAR2(100), Test Case 3: Dropping a Table
operation_user VARCHAR2(50), Execute the following command:
DROP TABLE customer_feedback;
timestamp DATE Validate: Query the audit log:
);
SELECT * FROM audit_ddl_log
Step 2: Create the DDL Trigger ORDER BY TIMESTAMP DESC;
This trigger will log relevant details whenever a DDL operation occurs.
Expected Output
CREATE OR REPLACE TRIGGER log_ddl_operations
AFTER CREATE OR ALTER OR DROP ON DATABASE
BEGIN
INSERT INTO audit_ddl_log (event_type, object_name, operation_user, timestamp)
VALUES (
ORA_SYSEVENT, -- Captures the type of event (e.g., CREATE, ALTER, DROP)
ORA_DICT_OBJ_NAME, -- Captures the affected object (e.g., table name)
SYS_CONTEXT('USERENV', 'SESSION_USER'), -- Captures the user performing the operation
SYSDATE -- Captures the timestamp of the operation
);
END;
/
Step 3. Testing
Test Case 1: Creating a Table
Execute the following command:
This implementation provides a robust mechanism to monitor and log critical schema changes in a
bank’s database, ensuring security and compliance.
Note:
▪ You do not manually call a trigger. Instead, it gets triggered automatically when the
defined DML operation (INSERT, UPDATE, DELETE) happens on the specified table (in this
case, EMPLOYEES).
▪ To test it, simply perform the corresponding DML operation (insert, update, or delete) on the
EMPLOYEES table.
▪ To see the output of the trigger, ensure DBMS_OUTPUT is enabled and perform the
operations.
19
II. Advanced Trigger Creation Assignment - Salary Change
Auditing
Scenario-Based Question :
You are a database developer managing the ICTCHEMBERADMIN.EMPLOYEES table. The HR department wants to track and audit every change made to employee salaries. This is
to ensure transparency and accountability whenever salary updates occur.
Your Task:
Additionally
▪ Create a stored procedure to perform a salary update that:
o Accepts employee_id and new_salary as input parameters.
o Performs the update to the EMPLOYEES table.
o Includes exception handling to raise an error when the employee_id does not exist or when any unexpected error occurs.
20
/*
Step 1: Create the SALARY_AUDIT Table
*/
--Step 1: Create the SALARY_AUDIT Table
CREATE TABLE salary_audit (
employee_id NUMBER(6), -- Employee's ID
old_salary NUMBER(8,2), -- Old salary value
new_salary NUMBER(8,2), -- New salary value
change_date DATE, -- Date (stores date and time)
timestamp_change TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp for change with default value
username VARCHAR2(30), -- Username of the person making the change
session_id VARCHAR2(30) -- Session ID of the user making the change
);
Solution approach –
Salary Audit
Step 2: Create the Trigger Deliverables:
▪Name the trigger: TRG_SALARY_AUDIT ▪SQL script for creating the SALARY_AUDIT table
▪It should fire only when the salary is actually ▪SQL script for the TRG_SALARY_AUDIT trigger
changed ▪A brief explanation (2–4 lines) of how your trigger works
▪Type of trigger:
BEFORE UPDATE ON EMPLOYEES FOR EACH ROW
▪Inside the trigger body, compare :OLD.salary and
:NEW.salary
▪If they are different, insert a new record into
SALARY_AUDIT with the required fields
21
CREATE OR REPLACE TRIGGER trg_salary_audit Step 3: Create the Trigger
BEFORE UPDATE ON employees
FOR EACH ROW
WHEN (OLD.salary != NEW.salary) -- Only fire if salary is being changed
BEGIN
BEGIN
-- Insert the salary change into the audit table
INSERT INTO salary_audit (
employee_id,
old_salary,
new_salary,
change_date,
username,
session_id
)
VALUES (
:OLD.employee_id,
:OLD.salary,
:NEW.salary,
Solution – Trigger Salary SYSDATE, -- Current system date and time
USER, -- Current database user
Audit );
SYS_CONTEXT('USERENV', 'SESSIONID') -- Current session ID
EXCEPTION
WHEN OTHERS THEN
-- Handle unexpected errors silently to avoid interrupting the original UPDATE
-- Optionally, log error into an error_log table (not shown here)
NULL; -- Replace with logging if desired
END;
END;
/
22
Step 3: Procedure to update salary
CREATE OR REPLACE PROCEDURE update_employee_salary (
p_employee_id IN NUMBER,
p_new_salary IN NUMBER
) AS
BEGIN
-- Update employee salary in the employees table
UPDATE employees
SET salary = p_new_salary
WHERE employee_id = p_employee_id;
END;
/*
/
Call the procedure and input id and salary to be changed.
*/
Solution – Procedure to -- Call the procedure
BEGIN
23
III. Creating a DML Trigger for Auditing Allowances Table
Operations
Scenario-Based Question:
3. Stored Procedures for DML Operations:
You are tasked with implementing an audit mechanism to log all DML (Data Manipulation ▪ Write UPDATE and DELETE procedures for the ALLOWANCES table with exception
Language) operations (INSERT, UPDATE, DELETE) on critical tables in a banking system handling.
database. This ensures accountability and transparency by tracking changes made to key tables. ▪ If an error occurs, log it in an error log table.
/*
Step 2: Create the DML Trigger
Solution - DML Trigger - Now, let's create a DML Trigger for each table (e.g., ALLOWANCES, ATTENDANCE, COUNTRIES, DEPARTMENTS,
EMPLOYEES, ROLES). This trigger will capture the changes made (insertion, update, deletion) to any of the tables and log
those changes in the audit_dml_log table.
Auditing Allowances */
CREATE OR REPLACE TRIGGER log_dml_operations
Operations (1/4) AFTER INSERT OR UPDATE OR DELETE ON ALLOWANCES -- You can change this table name dynamically if needed
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO audit_dml_log (operation_type, object_name, operation_user, timestamp, new_data)
VALUES ('INSERT', 'ALLOWANCES', SYS_CONTEXT('USERENV', 'SESSION_USER'), SYSDATE,
:NEW.ALLOWANCE_AMOUNT);
ELSIF UPDATING THEN
SYS_CONTEXT('USERENV', 'SESSION_USER') is an INSERT INTO audit_dml_log (operation_type, object_name, operation_user, timestamp, old_data, new_data)
Oracle SQL function used to retrieve information VALUES ('UPDATE', 'ALLOWANCES', SYS_CONTEXT('USERENV', 'SESSION_USER'), SYSDATE,
about the current session, specifically the session
:OLD.ALLOWANCE_AMOUNT, :NEW.ALLOWANCE_AMOUNT);
user (i.e., the user currently connected to the
ELSIF DELETING THEN
database).
INSERT INTO audit_dml_log (operation_type, object_name, operation_user, timestamp, old_data)
VALUES ('DELETE', 'ALLOWANCES', SYS_CONTEXT('USERENV', 'SESSION_USER'), SYSDATE,
:OLD.ALLOWANCE_AMOUNT);
END IF;
END;
/
25
/*
Step 3: Repeat for Other Tables
You can repeat the process for other tables (ATTENDANCE, COUNTRIES, DEPARTMENTS, EMPLOYEES, ROLES)
by changing the AFTER INSERT OR UPDATE OR DELETE ON part of the trigger, and modifying the field names in the
:NEW and :OLD references according to the specific columns in those tables.
For example, for the ATTENDANCE table, the trigger would look like this:
*/
26
CREATE OR REPLACE PROCEDURE update_allowance( update_allowance with exception handling
p_allowance_id IN NUMBER,
p_new_amount IN NUMBER
) AS
e_id_not_found EXCEPTION;
PRAGMA EXCEPTION_INIT(e_id_not_found, -20001);
BEGIN
UPDATE ALLOWANCES
SET ALLOWANCE_AMOUNT = p_new_amount
WHERE ALLOWANCE_ID = p_allowance_id;
IF SQL%ROWCOUNT = 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Allowance ID does not exist.');
END IF;
COMMIT;
Test – Update EXCEPTION
WHEN e_id_not_found THEN
Allowances RAISE;
WHEN OTHERS THEN
--Call update_allowance
/
BEGIN
update_allowance(12, 6000);
END;
/
27
delete_allowance
CREATE OR REPLACE PROCEDURE delete_allowance(
p_allowance_id IN ALLOWANCE_ID NUMBER
) AS
BEGIN
DELETE FROM ALLOWANCES
WHERE ALLOWANCE_ID = p_allowance_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO audit_dml_error_log (error_message, error_time, object_name, operation_user)
VALUES (SQLERRM, SYSDATE, 'ALLOWANCES', SYS_CONTEXT('USERENV', 'SESSION_USER'));
RAISE;
END; BEGIN
/ delete_allowance(12);
END;
Attendance (3/4) ) AS
BEGIN
UPDATE ATTENDANCE
SET STATUS = p_new_status
WHERE ATTENDANCE_ID = p_attendance_id;
IF SQL%ROWCOUNT = 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Attendance ID does not exist.');
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
--Call update_allowance
ROLLBACK;
BEGIN
RAISE;
END; update_attendance(101, 'Present');
/ END;
/ 28
delete_attendance
CREATE OR REPLACE PROCEDURE delete_attendance(
p_attendance_id IN NUMBER
) AS
BEGIN
DELETE FROM ATTENDANCE
WHERE ATTENDANCE_ID = p_attendance_id;
IF SQL%ROWCOUNT = 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Error: Attendance ID does not exist.');
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20002, 'Unexpected error occurred while deleting attendance: ' ||
SQLERRM); BEGIN
END; delete_attendance(101);
/ END;
/
Test – Delete
Attendance (4/4)
29
/*
Step 4: Test the Trigger
Let's perform some operations on the ALLOWANCES table to verify that the trigger is working as expected.
Tables (3/3) /*
Output Check the audit log:
*/
SELECT * FROM audit_dml_log;
-- DML logs
SELECT * FROM audit_dml_log ORDER BY timestamp DESC;
30
IV. Database Error Logging with Trigger – Practical Task
Scenario-Based Question
You are working as a Database Administrator in an organization where it is critical to log all DML (Data Manipulation Language) errors for audit and debugging purposes. Your goal is to
ensure that whenever a DML error occurs (e.g., due to a constraint violation), a trigger automatically logs the error details into a table called dml_error_log.
Task Overview
Instructions
▪ Run the table and trigger creation script to set up the environment.
▪ Choose or create a sample table for testing.
31
CREATE TABLE dml_error_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY,
error_message VARCHAR2(4000),
error_time TIMESTAMP DEFAULT SYSTIMESTAMP,
object_name VARCHAR2(128),
action VARCHAR2(30),
session_id NUMBER,
username VARCHAR2(128),
sql_text CLOB,
CONSTRAINT pk_dml_error_log PRIMARY KEY (log_id)
);
32
CREATE OR REPLACE TRIGGER trg_log_dml_errors
--fire automatically after any error occurs | AFTER SERVERERROR Trigger activates after an error occurs
AFTER SERVERERROR ON SCHEMA
DECLARE
v_error_stack VARCHAR2(4000);
v_object_name VARCHAR2(128);
v_action VARCHAR2(30);
BEGIN
-- Get the error information
v_error_stack := DBMS_UTILITY.FORMAT_ERROR_STACK;
-- Determine which object and action caused the error | For demonstration, we'll check the current SQL statement
Trigger Definition :
v_action := 'ALTER';
ELSE
v_action := 'UNKNOWN';
END IF;
Output
34
System Event Trigger Definition
A system event trigger in a database is used to automatically execute a PL/SQL block of code in response to certain predefined system-level events. These events are not
associated with any specific table but are linked to database operations like user logins, database startup or shutdown, and DDL (Data Definition Language) changes.
Common Events for System Triggers:
▪ LOGON: Triggered when a user logs into the database.
▪ LOGOFF: Triggered when a user logs off from the database.
▪ STARTUP: Triggered when the database is started.
▪ SHUTDOWN: Triggered when the database is shut down.
▪ AFTER SERVERERROR: Triggered after a server error occurs.
▪ AFTER DDL: Triggered after a DDL statement (e.g., CREATE, ALTER, DROP) is executed.
▪ BEFORE DDL: Triggered before a DDL statement is executed.
CREATE TABLE, ALTER TABLE, etc. DDL Defines and modifies the structure of database objects
INSERT, UPDATE, DELETE DML (Data Manipulation Language) Changes data inside tables
GRANT, REVOKE DCL (Data Control Language) Manages permissions and access controls
Login/Logoff auditing DBMS auditing or security features Typically handled by database configuration or logs
36
This trigger captures login events and logs them into a custom USER_LOG table.
-- Create a table to log user activity Create Audit Table for Login Logs
CREATE TABLE USER_LOG (
LOG_ID NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- Unique identifier for each log entry
USERNAME VARCHAR2(50), -- Stores the username of the logged-in user
SESSION_ID NUMBER, -- Tracks the session ID of the user
LOGON_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Records the logon time (defaults to the current time)
);
-- Specify that the trigger fires AFTER a LOGON event on the entire DATABASE
AFTER LOGON ON DATABASE
BEGIN
-- Insert a record into the USER_LOG table for every user logon
Output
/*
Check the USER_LOG Table:
Log in to the database as the user who created the trigger and
verify the records.
Query the USER_LOG table:
*/
-- Specify that the trigger fires AFTER any DDL (Data Definition Language) operation
on the current schema
AFTER DDL ON SCHEMA
BEGIN
II. Logging User -- Insert a record into the DDL_LOG table for every DDL operation
INSERT INTO DDL_LOG (
USERNAME, -- The user performing the DDL operation
Logins SCHEMA_NAME,
EVENT_TYPE,
-- The schema where the DDL operation is being executed
-- The type of DDL event (e.g., CREATE, ALTER, DROP)
OBJECT_NAME, -- The name of the object affected by the DDL event (e.g.,
table, view, etc.)
TIMESTAMP -- The timestamp when the DDL operation occurred
)
VALUES (
USER, -- Built-in function returning the username
SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'), -- Retrieves the current
schema name
ORA_SYSEVENT, -- Built-in variable for the type of DDL event
(e.g., CREATE, ALTER, DROP)
ORA_DICT_OBJ_NAME, -- Built-in variable for the name of the
object involved in the DDL operation
SYSTIMESTAMP -- Captures the current date and time
);
END trg_ddl_audit;
/ 38
/*
Step 1: Ensure the DDL_LOG Table Exists
Before testing, make sure the DDL_LOG table is created and ready to store audit records:
*/
SELECT * FROM DDL_LOG;
Output
39
-- Create the logging table
CREATE TABLE shutdown_log (
log_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
event_type VARCHAR2(100),
event_message VARCHAR2(4000)
);
A pre-shutdown trigger
-- Create a before shutdown trigger (fixed version)
CREATE OR REPLACE TRIGGER trg_before_shutdown
BEFORE SHUTDOWN ON DATABASE
BEGIN
INSERT INTO shutdown_log (event_type, event_message)
VALUES ('PLANNED_SHUTDOWN', 'Database shutdown initiated through normal command');
COMMIT;
EXCEPTION
Shutdown/resta
BEGIN
INSERT INTO shutdown_log (event_type, event_message)
VALUES ('SHUTDOWN_ERROR', 'Error during shutdown trigger: ' ||
rts Events DBMS_UTILITY.FORMAT_ERROR_STACK);
COMMIT;
EXCEPTION A pre-shutdown trigger
WHEN OTHERS THEN •System state views monitoring
NULL; -- Silent failure as last resort •Alert log monitoring
END;
END;
/
41
-- Check the log table
SELECT * FROM shutdown_log ORDER BY event_time DESC;
Output
42
IV. Trigger Event: Enforcing HR Transaction Restrictions
During Non-Working Hours
Scenario-Based Question:
The Human Resources Department of a large organization manages allowances for its employees. As part of the organizational policy, it is required that any changes to the
ALLOWANCES table—whether it be inserting new allowances, updating existing records, or deleting them—should only be allowed during official working hours (from 6:00 AM to 6:00
PM). This policy is designed to ensure that only authorized personnel, during working hours, can make changes to employee allowances.
If an attempt is made to insert, update, or delete records outside of these hours (e.g., during the night or weekends), the system should automatically block such attempts and raise an
appropriate error message to inform the user of the restriction.
Task:
As a database developer, you are tasked with implementing a PL/SQL trigger that enforces this policy on the ALLOWANCES table. The trigger should:
1. Fire before any INSERT, UPDATE, or DELETE operation on the ALLOWANCES table.
2. Check the system's current time to ensure it falls within the allowed timeframe of 7:00 AM to 6:00 PM.
3. If the operation is attempted outside these hours, raise an exception with the following message:
"Operations on the ALLOWANCES table are only allowed between 6:00 AM and 6:00 PM."
Deliverable:
▪ Write a PL/SQL trigger that implements the described functionality.
43
CREATE OR REPLACE TRIGGER restrict_allowance_hours
BEFORE INSERT OR UPDATE OR DELETE ON ALLOWANCES
FOR EACH ROW
DECLARE
-- Declare an exception to handle invalid transaction time NEW is a reference to the new values being inserted o
invalid_time EXCEPTION; updated in the table. Specifically, :NEW refers to the
v_current_hour NUMBER; record being affected by the INSERT or UPDATE
BEGIN
-- Check the current time in 24-hour format
operation in the ALLOWANCES table.
v_current_hour := TO_NUMBER(TO_CHAR(SYSDATE, 'HH24'));
HR Transaction
RAISE_APPLICATION_ERROR(-20003, 'Allowance amount cannot be negative.');
END IF;
Restriction
-- If the effective date is in the past, raise an exception
IF :NEW.EFFECTIVE_DATE < SYSDATE THEN
RAISE_APPLICATION_ERROR(-20004, 'Effective date cannot be in the past.');
END IF;
EXCEPTION
WHEN invalid_time THEN
-- Handle invalid time exception with custom message
RAISE_APPLICATION_ERROR(-20002, 'Operations on the ALLOWANCES table are only allowed between 7:00 AM and 6:00 PM.');
WHEN OTHERS THEN
-- Generic exception handler for unexpected errors
RAISE_APPLICATION_ERROR(-20001, 'An unexpected error occurred: ' || SQLERRM);
END;
44
/*
1. Valid Transaction (Within Working Hours):
*/
-- Example: Insert at 10:00 AM with valid data
INSERT INTO ALLOWANCES (ROLE_ID, ALLOWANCE_AMOUNT, EFFECTIVE_DATE, IS_APPLICABLE, COMMENTS)
VALUES (1, 500, SYSDATE + 1, 'Y', 'Annual Bonus');
-- Success: Operation allowed.
/*
2. Invalid Transaction (Outside Working Hours):
*/
-- Example: Insert at 8:00 PM (outside working hours)
INSERT INTO ALLOWANCES (ROLE_ID, ALLOWANCE_AMOUNT, EFFECTIVE_DATE, IS_APPLICABLE, COMMENTS)
VALUES (2, 600, SYSDATE + 1, 'Y', 'Holiday Allowance');
-- Error: "Operations on the ALLOWANCES table are only allowed between 6:00 AM and 6:00 PM."
Test: Enforcing HR
/*
3. Invalid Transaction (Negative Allowance Amount):
*/
Transaction -- Example: Insert with a negative allowance amount
INSERT INTO ALLOWANCES (ROLE_ID, ALLOWANCE_AMOUNT, EFFECTIVE_DATE, IS_APPLICABLE, COMMENTS)
/*
4. Invalid Transaction (Effective Date in the Past):
*/
-- Example: Insert with an effective date in the past
INSERT INTO ALLOWANCES (ROLE_ID, ALLOWANCE_AMOUNT, EFFECTIVE_DATE, IS_APPLICABLE, COMMENTS)
VALUES (4, 300, SYSDATE - 1, 'Y', 'Retroactive Allowance');
-- Error: "Effective date cannot be in the past."
/*
5. Invalid Transaction (Null Comments):
*/
-- Example: Insert with no comments provided
INSERT INTO ALLOWANCES (ROLE_ID, ALLOWANCE_AMOUNT, EFFECTIVE_DATE, IS_APPLICABLE, COMMENTS)
VALUES (5, 400, SYSDATE + 1, 'Y', NULL);
-- Error: "Comments are required."
45
Test out of working hours
Test: Enforcing HR
Transaction
Restriction Trigger
46
Scenario-Based Question: Trigger Event, Restricting Bank
Transactions Outside Working Hours
The Bank of Kigali has introduced a new operational policy aimed at strengthening compliance and enhancing system security. According to this policy, tellers are prohibited from
recording transactions outside official working hours.
Business Requirements:
▪ Transactions may only be recorded Monday through Friday, between 9:00 AM and 6:00 PM.
▪ Any attempt to record a transaction outside these hours or on weekends (Saturday or Sunday) must be automatically blocked by the database system.
47
-- Step 1: Create a sample transactions table (if it doesn't already exist)
CREATE TABLE transactions (
transaction_id NUMBER PRIMARY KEY,
teller_id NUMBER,
transaction_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
amount NUMBER
);
Event - Restricting
RAISE_APPLICATION_ERROR(-20001,
'Transactions can only be recorded between 9:00 AM and 6:00 PM, Monday to Friday.');
ELSIF TO_CHAR(SYSDATE, 'HH24MI') < '0900' OR TO_CHAR(SYSDATE, 'HH24MI') > '1800' THEN
Bank Transactions -- Raise an exception for outside working hours
RAISE_APPLICATION_ERROR(-20002,
'Transactions can only be recorded between 9:00 AM and 6:00 PM, Monday to Friday.');
END IF;
END;
/
/*
Testing the Trigger Success: Transaction is recorded.
1. Valid Transaction:
*/
-- Example of a valid transaction (Monday at 10:00 AM)
INSERT INTO transactions (transaction_id, teller_id, amount)
VALUES (1, 101, 500);
48
/*
Testing the Trigger -- Example of a valid transaction (Monday at 10:00 AM)
1. Valid Transaction:
*/
INSERT INTO transactions (transaction_id, teller_id, amount)
VALUES (1, 101, 500);
-- Error: "Transactions can only be recorded between 9:00 AM and 6:00 PM, Monday to Friday."
/*
Invalid Transaction (Weekend): -- Example of a transaction attempted on a Saturday
*/
INSERT INTO transactions (transaction_id, teller_id, amount)
VALUES (2, 102, 1000);
Transactions
Output
49
Trigger Event: Before Update Trigger to Enforce Salary
Protection in Employees Table
-- Trigger to prevent salary reduction in the 'employees' table
Question: CREATE OR REPLACE TRIGGER prevent_salary_reduction
-- The trigger will fire before any update on the salary column in the employees table
Suppose you are managing an employees table where each employee has BEFORE UPDATE OF salary ON employees
a salary that should not be decreased. Write a trigger named FOR EACH ROW -- Specifies that the trigger will execute once for each row being updated
prevent_salary_reduction that prevents any update to the salary column if BEGIN
the new salary is lower than the existing salary. -- Check if the new salary is less than the old salary
IF :NEW.salary < :OLD.salary THEN
The trigger should meet the following requirements: -- Raise an application error if the new salary is less than the old salary
1. It should be a BEFORE UPDATE trigger, so it checks the salary RAISE_APPLICATION_ERROR(-20001, 'Salary reduction is not allowed.');
change before the update is applied. END IF;
2. It should raise an error with the message "Salary reduction is not END;
allowed." if an attempt is made to reduce an employee's salary. /
3. Use RAISE_APPLICATION_ERROR with a custom error code to handle
this restriction.
--Test my trigger
UPDATE employees
Provide the full trigger code and explain each part of the code in
SET salary = 2500000
comments.
WHERE employee_id = 5;
50
Test Trigger Event Salary Reduction
51
Creating a Trigger to Log Employee Salary Changes and
Operations
Suppose you are tasked with creating a trigger that logs salary changes for employees, but only for those whose ROLE_ID is not equal to 1 (assuming role 1 is the Manager). The
trigger should work for INSERT, UPDATE, or DELETE operations on the EMPLOYEES table.
1. The trigger should be fired before an INSERT, UPDATE, or DELETE operation on the EMPLOYEES table.
2. It should log the following details for each type of operation:
▪ For an UPDATE operation: The old and new salary values and the difference between them.
▪ For an INSERT operation: The name of the new employee and their starting salary.
▪ For a DELETE operation: The name of the deleted employee and their final salary.
3. The trigger should only log changes for employees who do not have the role of Manager (ROLE_ID <> 1).
4. Make use of the DBMS_OUTPUT.PUT_LINE procedure to display the logged information.
You should handle all operations appropriately within the trigger, using the UPDATING, INSERTING, and DELETING conditions to check the operation type.
Hint: Use the :NEW and :OLD references to capture the values of the columns before and after the operations.
52
Trigger Event: Log Employee Salary Changes and Operations
– Solution
A BEFORE trigger is executed just before the DML operation (INSERT, UPDATE, or An INSTEAD OF trigger replaces the default behavior of a DML operation on a view.
DELETE) is performed on a table or view.
Purpose: It allows you to define exactly what should happen instead of the normal
Purpose: It’s typically used to validate or modify data before the operation takes INSERT, UPDATE, or DELETE operation.
place.
Important: The DML operation will still execute unless: Why needed: Views generally do not support direct DML operations—especially when
▪You explicitly raise an error (e.g., with RAISE_APPLICATION_ERROR) they are based on multiple tables or contain complex joins. INSTEAD OF triggers make
▪Or take some other action that prevents it such views updatable.
Summary Table
Trigger Type When It Executes Used On Default Action
BEFORE Before the DML runs Tables Operation proceeds unless stopped
INSTEAD OF Replaces the DML logic Views Custom logic fully replaces default behavior
54
/*
2. Create the INSTEAD OF Trigger:
*/ /*1. Create the View (if not already created):*/
CREATE OR REPLACE TRIGGER log_salary_changes
INSTEAD OF INSERT OR UPDATE OR DELETE ON EMPLOYEES_VIEW CREATE OR REPLACE VIEW EMPLOYEES_VIEW AS
FOR EACH ROW SELECT EMPLOYEE_ID, LAST_NAME, SALARY
DECLARE FROM EMPLOYEES;
sal_diff NUMBER;
BEGIN
-- Handling INSERT operation
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('Inserting New Employee: ' || :NEW.LAST_NAME);
DBMS_OUTPUT.PUT_LINE('Starting Salary: ' || :NEW.SALARY);
-- Perform actual insert action
INSERT INTO EMPLOYEES (EMPLOYEE_ID, LAST_NAME, SALARY)
VALUES (:NEW.EMPLOYEE_ID, :NEW.LAST_NAME, :NEW.SALARY);
55
Instead Of Event: Log Employee Salary Changes
and Operations – Solution
View-Based Operations
▪ The trigger is defined on a view named EMPLOYEES_VIEW, not directly on the base table EMPLOYEES.
▪ This approach allows controlled manipulation of data presented through the view, especially when the view is complex or combines multiple tables.
INSTEAD OF Trigger
▪ The INSTEAD OF trigger intercepts INSERT, UPDATE, and DELETE operations on the view.
▪ It allows you to define custom logic that replaces the default behavior—like logging, validating, or rerouting the changes to the underlying table (EMPLOYEES in this case).
Use of DBMS_OUTPUT
▪ The DBMS_OUTPUT.PUT_LINE procedure is used for logging purposes.
▪ It prints useful information (like salary differences) to help with debugging or auditing.
Custom Actions
▪ The trigger can include custom logic, such as logging operations to a separate audit table, enforcing rules, or notifying users.
▪ After logging or validation, the actual DML operation is performed manually on the EMPLOYEES table from within the trigger body.
Important Considerations
56
Oracle Trigger Execution Order with FOLLOWS Clause
In Oracle, you can define multiple triggers for the same timing point (e.g., BEFORE INSERT, AFTER UPDATE). However, before Oracle 11g, their execution order was not
guaranteed, which could cause inconsistent behavior in complex systems.
Starting with Oracle 11g, the FOLLOWS clause allows you to explicitly control the execution order of such triggers. This ensures predictable and consistent behavior when multiple triggers
are defined for the same timing point.
Example: The following demonstrates how to create a table and two BEFORE INSERT triggers, using FOLLOWS to define their execution order.
▪ Table Created
▪ Trigger 1 created ▪ Trigger 2 created
57
SET SERVEROUTPUT ON; ▪ Insert data in table trigger_follows_test
▪ Verify our records from the table
-- Test the triggers by inserting a record ▪ Trigger 3 created
INSERT INTO trigger_follows_test (id, description) ▪ Insert again data in table trigger_follows_test
VALUES (1, 'Testing trigger execution order');
Triggers
Output
Clean up (optional)
DROP TABLE trigger_follows_test CASCADE
CONSTRAINTS;
58
Oracle Trigger Execution Order with FOLLOWS
Clause - Summary
The FOLLOWS clause is especially useful in complex systems where triggers rely on
the output of one another.
59
Compound Triggers in Oracle PL/SQL
Share Data Across Timing Improve Performance with Avoid Mutating Table
Points Bulk Operations Errors
A compound trigger in PL/SQL (introduced in Oracle 11g) is a
powerful feature that allows you to define multiple trigger timing
points—such as:
▪ BEFORE STATEMENT
▪ BEFORE EACH ROW
▪ AFTER EACH ROW By deferring certain
Instead of processing operations and using
▪ AFTER STATEMENT Compound triggers let
each row individually, temporary storage,
—within a single trigger block on the same table. you share variables and
you can collect data compound triggers help
temporary data across
during row-level events prevent mutating
different timing
This unified structure helps you manage complex business logic more and process it in bulk in table errors, which
sections, enabling
efficiently and avoids common issues like the mutating table the AFTER STATEMENT occur when a trigger
consistent and
section—boosting accesses or modifies
error, which can occur with regular row-level triggers. simplified processing.
performance. the table that caused it
to fire.
60
Restrictions of Compound Triggers
1 2 3 4
Use Shared Variables: Apply Bulk Processing: Keep Logic Modular: Prevent Mutating Table
Declare variables in the Collect data during row-level Distribute logic cleanly across Errors:
trigger body to share data sections and process it in bulk timing points. Avoid Temporarily store row-level
across timing points. in the AFTER STATEMENT overloading any single section data and act on it in AFTER
section for better with complex code. STATEMENT to avoid
performance. accessing the table while
it's being modified.
62
Advantages of Compound Triggers
Simplified Maintenance:
Performance Boost: Error Prevention: Enhanced Flexibility:
Combines logic across multiple
Improves performance with bulk Helps avoid mutating table Allows logic to execute at
timing points into one unified
processing, especially in high- errors and other common trigger different stages of the DML
trigger, reducing code
volume operations. pitfalls. lifecycle.
duplication.
63
CREATE OR REPLACE TRIGGER trigger_name
FOR INSERT OR UPDATE OR DELETE ON object_name
[REFERENCING OLD AS old NEW AS new]
COMPOUND TRIGGER
Optional Section
-- Declaration Section (optional)
-- Shared between all timing points
variable_name datatype;
Compound
BEGIN
-- Code executed before each row operation
EXCEPTION
END trigger_name; 64
“The function of education is to teach one
to think intensively and to think critically"
— Martin Luther King Jr.
65
CREATE OR REPLACE TRIGGER trg_student_changes
FOR INSERT OR UPDATE OR DELETE ON students
COMPOUND TRIGGER
Example of
IF INSERTING OR UPDATING THEN ELSIF UPDATING THEN
IF :NEW.gpa < 0 OR :NEW.gpa > 5 THEN DBMS_OUTPUT.PUT_LINE('Updated: From GPA ' || :OLD.gpa || ' to '
RAISE_APPLICATION_ERROR(-20001, 'GPA must be between 0 and 5');
|| :NEW.gpa);
Compound (e.g.
END IF;
ELSIF DELETING THEN
-- Ensure student name is not NULL DBMS_OUTPUT.PUT_LINE('Deleted: ' || :OLD.student_name);
END trg_student_changes;
/
66
Example of
Compound (e.g. Test by updating
Test by delete
DELETE students
WHERE studentId = 15;
67
Example: Auditing Data Changes with a Compound Trigger
How can we use a compound trigger to track and log salary changes (inserts, updates, and deletes) on the EMPLOYEES table into an AUDIT_EMP table, while ensuring performance
and avoiding mutating table errors?
➔ Purpose
The compound_salary_audit trigger tracks salary changes on the EMPLOYEES table and stores them in a separate salary_audit table using bulk processing for better performance and
to avoid mutating table errors. write this clearly as a question
Object Type and Nested Table
Objects Involved
-- Audit Table -- Create an object type to represent a single employee's salary change
CREATE OR REPLACE TYPE employee_salary_obj AS OBJECT (
CREATE TABLE salary_audit ( employee_id NUMBER, -- Employee's ID
employee_id NUMBER, old_salary NUMBER, -- Salary before the update
old_salary NUMBER, new_salary NUMBER -- Salary after the update
new_salary NUMBER, );
change_date DATE /
);
-- Create a nested table type to store multiple employee salary change records
CREATE OR REPLACE TYPE employee_salary_tab IS TABLE OF employee_salary_obj;
/
68
-- Create a compound trigger to audit salary updates in the EMPLOYEES table
CREATE OR REPLACE TRIGGER compound_salary_audit
FOR UPDATE OF SALARY ON EMPLOYEES
COMPOUND TRIGGER
-- Declare a nested table variable to collect salary changes during the statement
salary_changes employee_salary_tab := employee_salary_tab();
-- BEFORE EACH ROW section: captures the salary change before each row is updated
BEFORE EACH ROW IS
BEGIN
-- Extend the nested table to add a new entry
salary_changes.EXTEND;
-- Store the current row's employee ID, old salary, and new salary
salary_changes(salary_changes.COUNT) := employee_salary_obj(
Shared Object );
END BEFORE EACH ROW;
Type - Trigger -- AFTER STATEMENT section: runs once after all row updates are done
AFTER STATEMENT IS
Logic
BEGIN
-- Loop through the collected changes and insert them into the audit table
FOR i IN 1 .. salary_changes.COUNT LOOP
INSERT INTO salary_audit (
employee_id,
old_salary,
new_salary,
change_date
) VALUES (
salary_changes(i).employee_id,
salary_changes(i).old_salary,
salary_changes(i).new_salary,
SYSDATE
); -- Update salaries by 10% for employees in department 3
END LOOP; UPDATE EMPLOYEES
SET SALARY = SALARY * 1.10
-- Clear the nested table after inserting audit records WHERE DEPARTMENT_ID = 3;
salary_changes.DELETE;
END AFTER STATEMENT;
-- Verify audit logs
END compound_salary_audit; SELECT * FROM salary_audit;
/ 69
Key Benefits
▪ Performance: Uses bulk logging instead of row-by-row INSERTs.
▪ Prevents Mutating Table Errors: Defers DML to AFTER STATEMENT.
▪ Structured Data: Uses object types and nested tables for clean handling.
Output
Output
70
Question: Compound of Maintaining Employee Salary
Records Automatically
Scenario: Tasks:
Your company maintains two tables: 1. Write a Compound Trigger:
1. EMPLOYEES: Stores EMPLOYEE_ID, SALARY, and BONUS. ▪ Use a compound trigger to ensure the following:
2. EMPLOYEE_SALARIES: Tracks employee salary and bonus details for payroll. o During the statement-level operation, initialize necessary structures (if
needed).
Requirement: o At the row-level operation, update or insert into the EMPLOYEE_SALARIES
Whenever an employee is added or their SALARY or BONUS is updated in the EMPLOYEES table as required.
table, ensure that the EMPLOYEE_SALARIES table is updated to reflect the changes. Use a o Log any errors explicitly.
compound trigger to manage this logic efficiently. If the employee does not exist in ▪ Handle duplicate records gracefully to avoid conflicts in the EMPLOYEE_SALARIES
table.
EMPLOYEE_SALARIES, insert a new record.
2. Add Exception Handling:
Database Schema:
EMPLOYEES: ▪ Explicitly handle exceptions for UPDATE or INSERT operations.
▪ EMPLOYEE_ID (Primary Key)
▪ Log meaningful error messages for failures (e.g., primary key violations).
▪ SALARY
▪ BONUS 3. Test the Trigger:
EMPLOYEE_SALARIES: ▪ Insert a new employee into the EMPLOYEES table and verify changes in
▪ EMPLOYEE_ID (Primary Key) EMPLOYEE_SALARIES.
▪ SALARY ▪ Update an existing employee's SALARY or BONUS in EMPLOYEES and ensure the
changes are reflected in EMPLOYEE_SALARIES.
▪ BONUS
Validation Steps:
▪ Insert a new employee into EMPLOYEES and check the insertion into EMPLOYEE_SALARIES.
▪ Update an employee's salary or bonus and verify the update in EMPLOYEE_SALARIES.
▪ Test duplicate handling by attempting to insert an already existing record in
EMPLOYEE_SALARIES.
71
Scenario-Based Question: Auditing Student Data with a
Compound Trigger at AUCA
Problem Statement: Student Data Auditing with Compound Triggers
You are the database administrator for Adventist University of Central Africa (AUCA). Your objective is to track and audit changes made to student records using a compound
trigger. This ensures that any updates to the student data are automatically logged in an audit table for accountability and historical tracking.
Task Overview
Follow the steps below to design and implement the auditing system:
Data with a /*
Step 2: Insert Sample Data
Populate the students table with sample data:
assigned:
▪ A unique student_id from 1 to 1000,
Compound
▪ A name in the format "Student 1", "Student 2",
*/ ..., "Student 1000",
BEGIN ▪ A major chosen cyclically from Computer
Optional FOR i IN 1..1000 LOOP
INSERT INTO students (student_id, student_name, major, gpa)
Science, Engineering, Business, and Arts,
▪ A GPA ranging from 2.5 to 2.9, calculated using
VALUES ( a simple formula to add variation.
i, This approach is used to simulate realistic and diverse
'Student ' || i, student data for testing the audit logging system.
CASE MOD(i, 4)
WHEN 0 THEN 'Computer Science'
WHEN 1 THEN 'Engineering'
WHEN 2 THEN 'Business'
ELSE 'Arts'
END,
2.5 + MOD(i, 5) * 0.1
);
END LOOP;
END;
to Track Updates
student_changes.EXTEND;
student_changes(student_changes.COUNT) := student_audit_obj(:OLD.student_id);
END IF;
Table
AFTER STATEMENT IS
BEGIN
-- Bulk insert audit records for changed students
FOR i IN 1 .. student_changes.COUNT LOOP
INSERT INTO students_audit (
student_id,
action,
change_date
) VALUES (
student_changes(i).student_id,
'UPDATE',
SYSDATE
);
END LOOP;
END compound_students_audit;
/ 74
Output
-- Step 1: Update GPAs for all students whose GPA is currently below 4.0
-- This will trigger the compound trigger to log each update into the audit
table
UPDATE students
SET gpa = gpa + 0.5
WHERE gpa < 4.0;
Solution:
Compound Trigger Output
to Track Updates -- Step 2: Check the total number of records inserted into the
students_audit table
Test -- This should match the number of rows updated in the students
table
SELECT COUNT(*) FROM students_audit;
75
Scenario Question: Managing Allowances Based on
Attendance
Here's a scenario that incorporates the creation and use of a compound trigger to manage related data across the ALLOWANCES and ATTENDANCE tables. The trigger
ensures that when an employee's attendance record indicates absence, an allowance record is automatically marked as not applicable (IS_APPLICABLE = 'N').
Scenario: Managing Allowances Based on Attendance
Objective:
Ensure that allowances are correctly updated based on employee attendance records. If an employee is marked absent on a particular date, all allowance entries linked
to their role and effective on or before that date are marked as not applicable (IS_APPLICABLE = 'N').
Steps
1. Tables Involved:
▪ ALLOWANCES: Tracks allowances assigned to roles.
▪ ATTENDANCE: Records daily attendance for employees.
2. Business Rule:
▪ If an employee is marked as absent (STATUS = 'Absent') on a specific date:
o All allowances tied to the employee's role (ROLE_ID) and effective on or before the absence date (EFFECTIVE_DATE) must have their IS_APPLICABLE field
updated to 'N'.
3. Technical Requirements:
▪ Use a compound trigger to handle the update in a transaction-safe manner.
▪ Use an object type to manage allowances updates as part of the trigger logic.
76
Scenario Question: PL/SQL Compound Trigger Question:
Instagram System
Scenario:
You're working on the backend of an Instagram-like system where users can post pictures, like, comment, and follow other users. Your task is to implement compound triggers to
manage the operations within the system. A compound trigger allows you to group multiple trigger actions (such as INSERT, UPDATE, and DELETE) into a single trigger, which can
help to avoid potential issues with firing multiple triggers for the same event.
Requirements:
1.Create a Compound Trigger to Track New Posts:
▪ Every time a user posts a new picture, you need to automatically record the date and time of the post in a posts_audit table. This table has the following columns:
post_id, user_id, post_date.
Question:
▪ Write a compound trigger that will:
o Insert a record into the posts_audit table when a new post is added to the posts table.
2.Create a Compound Trigger for Comments on Posts:
▪ When a new comment is added to a post, you need to update the comments_count column in the posts table to reflect the new number of comments on that post.
Question:
▪ Write a compound trigger that will:
o Update the comments_count in the posts table whenever a new comment is added to a post in the comments table.
3.Create a Compound Trigger for User Follows:
▪ Every time a user follows another user, a notification should be sent to the followed user by inserting a new record into the notifications table. This table has the
following columns: notification_id, user_id, follower_id, notification_message, and notification_date.
Question:
▪ Write a compound trigger that will:
o Insert a record into the notifications table whenever a user follows another user.
4.Create a Compound Trigger to Prevent Multiple Posts in a Short Timeframe:
▪ If a user tries to post more than 5 times within 1 minute, the system should prevent the post from being added and raise an error message.
Question:
▪ Write a compound trigger that will:
o Restrict a user from posting more than 5 times within a minute and raise an appropriate error if the condition is met.
77
Scenario Question: PL/SQL Compound Trigger Question:
Instagram System
Evaluation Criteria:
▪ Use of Compound Triggers: Understanding how to use the AFTER STATEMENT, AFTER EACH ROW, and BEFORE STATEMENT sections effectively within a
compound trigger.
▪ Trigger Logic: Correct handling of multiple actions (insert, update, delete) within a single trigger body.
▪ Error Handling: Proper error handling and raising exceptions when necessary (e.g., for the restriction on multiple posts).
▪ Table Relationships: Correct understanding of the relationships between tables (e.g., posts, comments, notifications).
▪ Performance Considerations: Efficient use of compound triggers to manage multiple actions at once, avoiding redundant or unnecessary triggers.
Bonus Question:
▪ How would you modify the compound trigger to include a logging mechanism that tracks the status of the post (whether it's public or private) every time a new post is
added to the system?
78
Recap: PLSQL - Trigger
These triggers are fired in Combine multiple DML events These are fired when DDL Triggered based on system-
response to DML ▪Specifically designed for (INSERT, UPDATE, DELETE) statements are executed: level events, such as:
operations on tables or views. into a single trigger block. ▪CREATE, ALTER, DROP ▪LOGON / LOGOFF
views: Useful to:
▪Allow performing INSERT, ▪TRUNCATE, RENAME ▪STARTUP / SHUTDOWN
▪INSERT UPDATE, or DELETE on views ▪Handle complex business ▪GRANT, REVOKE Often used for monitoring,
▪UPDATE that normally don’t support rules, Mostly used for auditing or security checks, or logging
▪DELETE direct DML operations. ▪Prevent mutating table enforcing database user sessions.
They can be defined as ▪Executed instead of the errors, policies.
BEFORE, AFTER, or DML operation on the view. ▪Use bulk processing for
INSTEAD OF (on views). better performance.
79
Question:
You need to create a trigger in an Oracle database that automatically increases the salary of employees who were hired
in 2022 by 22.5% of their base salary. This trigger should activate after an INSERT or UPDATE operation on the
employees table to ensure that any new employee hired in 2022 receives the salary increase right away.
Problem Statement –
Create a Trigger
80
Solution
To accomplish this, you will define a DML Trigger that will execute after a new employee is inserted or an existing
employee's hiring date is updated. The trigger will check if the hiring date falls within the year 2022 and, if so, apply the
22.5% increase to the employee's salary.
Increment
DROP TRIGGER trg_increase_salary;
81
Insert record 1 employees_test
INSERT INTO employees_test (employee_id, first_name, hire_date, salary)
VALUES (3, 'Kaka', TO_DATE('2022-03-10', 'YYYY-MM-DD'), 7000);
-- Check result
SELECT * FROM employees_test WHERE employee_id = 3;
UPDATE employees_test
SET hire_date = TO_DATE('2022-09-01', 'YYYY-MM-DD'),
salary = 40000
WHERE employee_id = 3;
-- Check result
Solution: Salary
SELECT * FROM employees_test WHERE employee_id = 3;
Increment &
Update & Test
Output
82
Exercise: Enhancing Accountability and Insights Through
Employee Salary Change Tracking
Exercise: Enhancing Accountability and Insights Through Employee Salary Change Tracking
Problem Statement
Context:
In a fast-paced business environment, managing employee compensation is critical for retaining talent and fostering employee satisfaction. Salary adjustments—whether due to
performance evaluations, promotions, or market shifts—occur frequently and must be tracked transparently. A clear mechanism for monitoring these changes helps HR ensure
accountability and make data-driven compensation decisions.
Challenge:
How can the organization implement an effective strategy to monitor and analyze salary changes recorded in the EMPLOYEES table, ensuring transparency, accountability, and strategic
decision-making?
Questions to Explore:
1.How can we systematically log each salary change—including the old salary, new salary, and the difference—to create a reliable historical record of compensation adjustments?
2.What potential effects might salary changes have on employee performance, satisfaction, and organizational equity?
3.How can HR utilize the recorded salary change data to identify trends, assess fairness, and optimize compensation policies?
4.How can we implement this logging mechanism (e.g., using a trigger like display_salary_changes) in a way that minimizes performance overhead, especially during bulk data
operations?
Objective
Design and implement a robust mechanism (such as a trigger) that automatically logs all salary changes made to the EMPLOYEES table. This mechanism should support real-time
monitoring, empower HR with actionable insights, and promote fairness and transparency across the organization.
In a mining company like Ngali Mining Ltd, especially in a gold mining operation, it is essential to track changes related to the
management and allocation of resources like gold production and compensation adjustments. The company aims to ensure
transparency in its operations, monitor resources effectively, and maintain fair practices.
Given the MINES table in Ngali Mining Ltd's Gold Mining System, create a conditional trigger named log_gold_changes that
fires before any DELETE, INSERT, or UPDATE operation on the table. The trigger should only log gold-related changes for mines that
do not belong to the CEO or top executives. For other mines, it should log the mine name, old gold stock, new gold stock, and
the difference in gold.
Specifications:
▪ Trigger Activation:
The trigger should fire only when the mine’s owner is not the 'CEO' (or any top executives).
▪ Output Format:
The output should log the mine’s name, old gold stock, new gold stock, and the difference in gold.
Objective:
The goal of this trigger is to ensure that Ngali Mining Ltd can easily track and review changes in gold stock levels for all mines except
those owned by the CEO or top executives. This mechanism will help the company maintain a transparent record of resource changes,
Question: Tracking
aiding in operational decision-making and fair distribution of gold production.
Gold Change
84
Difference Between Cursor and Trigger in PL/SQL
85
Application of Triggers
Triggers are used to automatically execute PL/SQL code in response to specific database events like INSERT, UPDATE, DELETE, or DDL operations (CREATE, ALTER, DROP). They help
maintain data integrity, enforce business logic, audit activity, and automate data processes without user intervention.
Common Uses of Log data modifications Prevent invalid Recalculate fields on Apply rules beyond Keep related tables
Triggers automatically. transactions. changes. standard constraints. consistent.
E.g., Track old and new E.g., Block order E.g., Update BONUS or E.g., Prevent deleting a E.g., Delete linked
salaries when an insertion if a customer TAX when salary is parent record if related records when an
employee’s salary is exceeds their credit modified. child records exist. employee is removed.
updated. limit.
86
Be Cautious: What to Know Before Using Triggers
Triggers are used to automatically execute PL/SQL code in response to specific database events like INSERT, UPDATE, DELETE, or DDL operations (CREATE, ALTER, DROP). They help
maintain data integrity, enforce business logic, audit activity, and automate data processes without user intervention.
Triggers are special procedures that automatically execute in response to specific events on a table or view. They are commonly used to
enforce business rules, ensure data integrity, audit data changes, and automate workflows without manual intervention.
However, while triggers are powerful, they should be used with care:
87
You will never change your life until you change something you do daily. The secret of
your success is found in your daily routine.
– John C. Maxwell
88
Keep Learning!
89