1. What is a trigger in Oracle?
A trigger is a PL/SQL program that automatically executes when a specified event occurs on a table, view, schema, or database.
Common events:
- INSERT
- UPDATE
- DELETE
- DDL events such as CREATE, ALTER, DROP
- Database events such as LOGON, STARTUP
2. What is the basic syntax?
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH ROW
BEGIN
-- PL/SQL statements
END;
/
Example:
CREATE OR REPLACE TRIGGER trg_emp
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('Employee inserted');
END;
/
3. What is the difference between BEFORE and AFTER triggers?
BEFORE triggers execute before the DML operation.
CREATE OR REPLACE TRIGGER trg_emp_before
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
:NEW.created_date := SYSDATE;
END;
/
AFTER triggers execute after the DML operation.
CREATE OR REPLACE TRIGGER trg_emp_after
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
INSERT INTO employee_log(emp_id, log_date)
VALUES (:NEW.employee_id, SYSDATE);
END;
/
A common rule of thumb:
- Use BEFORE when you need to validate or modify
:NEWvalues. - Use AFTER when you want to perform an action after the row has been successfully changed.
4. What are :NEW and :OLD?
They are correlation variables used inside row-level triggers.
| Operation | :OLD | :NEW |
|---|---|---|
| INSERT | ❌ | ✅ |
| UPDATE | ✅ | ✅ |
| DELETE | ✅ | ❌ |
Example:
CREATE OR REPLACE TRIGGER trg_salary
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE(
'Old salary: ' || :OLD.salary ||
', New salary: ' || :NEW.salary
);
END;
/
5. Can a trigger modify :NEW?
Yes, in a BEFORE row-level trigger.
CREATE OR REPLACE TRIGGER trg_upper_name
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
:NEW.employee_name := UPPER(:NEW.employee_name);
END;
/
If you execute:
INSERT INTO employees(employee_id, employee_name)
VALUES (101, 'john');
The stored name becomes:
JOHN
You generally cannot assign to :NEW in an AFTER trigger.
6. What is a row-level trigger?
A row-level trigger executes once for every affected row.
It is identified by:
FOR EACH ROW
Example:
CREATE OR REPLACE TRIGGER trg_emp_update
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
INSERT INTO employee_log
VALUES (
:OLD.employee_id,
:OLD.salary,
:NEW.salary,
SYSDATE
);
END;
/
If an update affects 100 employees, the trigger executes 100 times.
7. What is a statement-level trigger?
A statement-level trigger executes once for the entire SQL statement, regardless of how many rows are affected.
CREATE OR REPLACE TRIGGER trg_emp_statement
AFTER UPDATE ON employees
BEGIN
DBMS_OUTPUT.PUT_LINE('Employee table updated');
END;
/
For:
UPDATE employees
SET salary = salary * 1.10;
Even if 1,000 rows are updated, the trigger executes once.
8. What is the difference between row-level and statement-level triggers?
| Feature | Row-level | Statement-level |
|---|---|---|
| Syntax | FOR EACH ROW | No FOR EACH ROW |
| Execution | Once per row | Once per statement |
| :OLD / :NEW | Available | Not available |
| Best for | Row-specific logic | Statement-level actions |
9. Can one trigger handle INSERT, UPDATE, and DELETE?
Yes.
CREATE OR REPLACE TRIGGER trg_emp_audit
AFTER INSERT OR UPDATE OR DELETE
ON employees
FOR EACH ROW
BEGIN
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('INSERT');
ELSIF UPDATING THEN
DBMS_OUTPUT.PUT_LINE('UPDATE');
ELSIF DELETING THEN
DBMS_OUTPUT.PUT_LINE('DELETE');
END IF;
END;
/
Oracle provides the following conditional predicates:
INSERTINGUPDATINGDELETING
These determine which event fired the trigger.
10. How do I prevent an invalid salary?
CREATE OR REPLACE TRIGGER trg_validate_salary
BEFORE INSERT OR UPDATE OF salary
ON employees
FOR EACH ROW
BEGIN
IF :NEW.salary < 0 THEN
RAISE_APPLICATION_ERROR(
-20001,
'Salary cannot be negative'
);
END IF;
END;
/
Now:
INSERT INTO employees(employee_id, salary)
VALUES (101, -5000);
produces an application error.
11. How do I automatically set a creation date?
CREATE OR REPLACE TRIGGER trg_created_date
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
:NEW.created_date := SYSDATE;
END;
/
This is a classic trigger use case.
However, for simple default values, a column DEFAULT is often preferable:
created_date DATE DEFAULT SYSDATE
12. How can I automatically update a modification date?
CREATE OR REPLACE TRIGGER trg_modified_date
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
:NEW.modified_date := SYSDATE;
END;
/
Every update automatically changes modified_date.
13. How do I create an audit trigger?
Suppose:
CREATE TABLE employee_audit (
employee_id NUMBER,
old_salary NUMBER,
new_salary NUMBER,
changed_by VARCHAR2(100),
changed_on DATE
);
Trigger:
CREATE OR REPLACE TRIGGER trg_salary_audit
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
INSERT INTO employee_audit
(
employee_id,
old_salary,
new_salary,
changed_by,
changed_on
)
VALUES
(
:OLD.employee_id,
:OLD.salary,
:NEW.salary,
USER,
SYSDATE
);
END;
/
Now a salary change automatically creates an audit record.
14. Can a trigger call a procedure?
Yes.
CREATE OR REPLACE TRIGGER trg_emp
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
send_employee_notification(:NEW.employee_id);
END;
/
This is often better than putting a large amount of business logic directly inside the trigger.
15. Can a trigger contain a COMMIT?
Normally, no.
This is invalid in a normal trigger:
BEGIN
INSERT INTO employee_log VALUES (...);
COMMIT;
END;
You will encounter:
ORA-04092: cannot COMMIT in a trigger
The trigger runs as part of the transaction that fired it.
16. What is a mutating table error?
A common Oracle trigger problem is:
ORA-04091: table ... is mutating
This can happen when a row-level trigger tries to query or modify the same table that caused the trigger to fire.
Example:
CREATE OR REPLACE TRIGGER trg_emp
BEFORE UPDATE ON employees
FOR EACH ROW
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_count
FROM employees;
END;
/
If the trigger fires because of an update to employees, querying employees from the row-level trigger can cause a mutating-table error.
17. How can I solve a mutating-table problem?
A compound trigger is one modern solution.
Conceptually:
CREATE OR REPLACE TRIGGER trg_emp
FOR UPDATE ON employees
COMPOUND TRIGGER
AFTER EACH ROW IS
BEGIN
-- Collect row information
NULL;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
-- Query employees here
NULL;
END AFTER STATEMENT;
END;
/
The important idea is to collect information at the row level and perform table-level processing in the AFTER STATEMENT section.
18. What is a compound trigger?
A compound trigger allows multiple timing sections within one trigger.
It can contain sections such as:
- BEFORE STATEMENT
- BEFORE EACH ROW
- AFTER EACH ROW
- AFTER STATEMENT
It is particularly useful for:
- Avoiding mutating-table problems
- Sharing state between timing sections
- Bulk processing
19. Can I disable a trigger?
Yes.
ALTER TRIGGER trg_emp DISABLE;
Enable it again:
ALTER TRIGGER trg_emp ENABLE;
For all triggers on a table:
ALTER TABLE employees DISABLE ALL TRIGGERS;
And:
ALTER TABLE employees ENABLE ALL TRIGGERS;
20. How do I drop a trigger?
DROP TRIGGER trg_emp;
21. How do I check whether a trigger is enabled?
Query:
SELECT trigger_name,
status
FROM user_triggers
WHERE table_name = 'EMPLOYEES';
Possible status:
- ENABLED
- DISABLED
22. Can a trigger be created on a view?
Yes. Oracle supports INSTEAD OF triggers on views.
Example:
CREATE OR REPLACE TRIGGER trg_view_insert
INSTEAD OF INSERT ON employee_view
FOR EACH ROW
BEGIN
INSERT INTO employees(employee_id, employee_name)
VALUES (:NEW.employee_id, :NEW.employee_name);
END;
/
Instead of Oracle directly performing the DML against the view, the trigger defines what should happen.
23. What is an INSTEAD OF trigger?
An INSTEAD OF trigger tells Oracle:
It is primarily useful for making complex or non-updatable views behave as though they can accept DML.
24. Can triggers fire other triggers?
Yes.
For example:
INSERT into EMPLOYEES
↓
Trigger A fires
↓
Trigger A updates DEPARTMENTS
↓
Trigger B fires
This is called cascading trigger execution.
Be careful because excessive trigger chaining can make application behavior difficult to understand and debug.
25. What is a trigger vs a stored procedure?
| Trigger | Procedure |
|---|---|
| Executes automatically | Called explicitly |
| Associated with an event/object | Independent program |
| Usually responds to DML/DDL/database events | Performs business/application logic |
| Cannot normally accept parameters like a procedure | Can accept parameters |
| Useful for auditing/validation | Useful for reusable business logic |
26. Trigger vs constraint — which should I use?
Prefer a constraint when the requirement can be expressed naturally as a constraint.
For example, instead of:
CREATE TRIGGER ...
IF salary < 0 THEN ...
prefer:
ALTER TABLE employees
ADD CONSTRAINT chk_salary
CHECK (salary >= 0);
Constraints are generally clearer and are enforced directly by Oracle.
Use triggers when you need behavior that constraints cannot easily provide, such as:
- Audit logging
- Automatically maintaining related information
- Complex event-based processing
- INSTEAD OF behavior for views
⭐ Common Oracle Trigger Interview Questions
- What is a trigger?
- What are BEFORE and AFTER triggers?
- What is a row-level trigger?
- What is a statement-level trigger?
- What are :OLD and :NEW?
- Can we modify :NEW in an AFTER trigger?
- What is an INSTEAD OF trigger?
- What is a mutating-table error?
- How do you solve a mutating-table problem?
- What is a compound trigger?
- Can a trigger contain COMMIT?
- Can a trigger call a procedure?
- Can one trigger handle INSERT/UPDATE/DELETE?
- How do you disable and enable a trigger?
- How do you find all triggers on a table?
- What is cascading trigger execution?
- Trigger vs procedure?
- Trigger vs constraint?
- When should you avoid triggers?
- How do you create an audit trigger?
A Good Interview Example to Remember
CREATE OR REPLACE TRIGGER trg_employee_audit
AFTER UPDATE OF salary
ON employees
FOR EACH ROW
BEGIN
INSERT INTO employee_audit
(
employee_id,
old_salary,
new_salary,
changed_by,
changed_on
)
VALUES
(
:OLD.employee_id,
:OLD.salary,
:NEW.salary,
USER,
SYSDATE
);
END;
/
"This is an AFTER row-level trigger. It fires whenever an employee's salary is updated.
:OLD gives the previous salary and :NEW gives the new salary, and the trigger stores the change in an audit table."
Key Takeaways
- BEFORE: Use when you need to validate or modify incoming values.
- AFTER: Use for auditing and follow-up actions.
- Row-level: Executes once for every affected row.
- Statement-level: Executes once for the entire SQL statement.
- :OLD: Represents the previous value.
- :NEW: Represents the new value.
- Compound trigger: Useful for combining row-level and statement-level processing.
- INSTEAD OF: Commonly used with views.
- ORA-04091: Indicates a mutating-table problem.
- Constraints: Prefer them when the rule can naturally be enforced using a constraint.
No comments:
Post a Comment