1. What is an INSTEAD OF trigger?
An INSTEAD OF trigger tells Oracle:
Example:
CREATE OR REPLACE TRIGGER trg_emp_view
INSTEAD OF INSERT ON emp_dept_v
FOR EACH ROW
BEGIN
INSERT INTO employees
(
employee_id,
first_name,
department_id
)
VALUES
(
:NEW.employee_id,
:NEW.first_name,
:NEW.department_id
);
END;
/
When a user executes:
INSERT INTO emp_dept_v
(
employee_id,
first_name,
department_id
)
VALUES
(
101,
'John',
10
);
Oracle executes the trigger's INSERT on employees instead of trying to insert directly into the view.
2. Why do we need INSTEAD OF triggers?
They are useful when a view cannot naturally be modified.
For example:
CREATE VIEW emp_dept_v AS
SELECT
e.employee_id,
e.first_name,
d.department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id;
This view combines data from two tables:
EMPLOYEES
+
DEPARTMENTS
↓
EMP_DEPT_V
If you try:
INSERT INTO emp_dept_v
VALUES (101, 'John', 'IT');
Oracle may not know how to distribute the values between the underlying tables.
An INSTEAD OF trigger can provide that logic.
3. On what objects can INSTEAD OF triggers be created?
INSTEAD OF triggers are primarily associated with views.
They are especially useful for:
- Complex views
- Join views
- Views involving multiple tables
- Views containing aggregations
- Views involving
DISTINCT - Views involving set operators such as
UNION
Example:
CREATE OR REPLACE TRIGGER trg_emp_dept
INSTEAD OF INSERT ON emp_dept_v
FOR EACH ROW
BEGIN
...
END;
/
4. Can an INSTEAD OF trigger be created on a table?
No.
You don't create an INSTEAD OF trigger on a normal table.
For tables, use:
BEFORE
AFTER
For example:
BEFORE INSERT ON employees
or:
AFTER UPDATE ON employees
INSTEAD OF → ViewBEFORE / AFTER → Table
5. Is an INSTEAD OF trigger row-level or statement-level?
An INSTEAD OF trigger is always a row-level trigger.
Therefore:
FOR EACH ROW
is required.
Example:
CREATE OR REPLACE TRIGGER trg_emp_view
INSTEAD OF INSERT ON emp_dept_v
FOR EACH ROW
BEGIN
...
END;
/
You cannot create:
CREATE OR REPLACE TRIGGER trg_emp_view
INSTEAD OF INSERT ON emp_dept_v
BEGIN
...
END;
/
without FOR EACH ROW.
INSTEAD OF trigger↓
Always row-level
↓
FOR EACH ROW is required
6. Can INSTEAD OF triggers use :OLD and :NEW?
Yes.
Because INSTEAD OF triggers are row-level triggers.
| Operation | :OLD |
:NEW |
|---|---|---|
| INSERT | ❌ | ✅ |
| UPDATE | ✅ | ✅ |
| DELETE | ✅ | ❌ |
7. Example of an INSTEAD OF INSERT trigger
Suppose we have:
CREATE TABLE employees (
employee_id NUMBER,
first_name VARCHAR2(50),
department_id NUMBER
);
Create a view:
CREATE VIEW emp_v AS
SELECT
employee_id,
first_name,
department_id
FROM employees;
Create the trigger:
CREATE OR REPLACE TRIGGER trg_emp_v_insert
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
INSERT INTO employees
(
employee_id,
first_name,
department_id
)
VALUES
(
:NEW.employee_id,
:NEW.first_name,
:NEW.department_id
);
END;
/
Now:
INSERT INTO emp_v
(
employee_id,
first_name,
department_id
)
VALUES
(
101,
'John',
10
);
The trigger performs:
INSERT INTO employees ...
instead of inserting directly into the view.
8. Example of an INSTEAD OF UPDATE trigger
Create a view:
CREATE VIEW emp_v AS
SELECT
employee_id,
first_name,
department_id
FROM employees;
Trigger:
CREATE OR REPLACE TRIGGER trg_emp_v_update
INSTEAD OF UPDATE ON emp_v
FOR EACH ROW
BEGIN
UPDATE employees
SET
first_name = :NEW.first_name,
department_id = :NEW.department_id
WHERE employee_id = :OLD.employee_id;
END;
/
Now:
UPDATE emp_v
SET first_name = 'Robert'
WHERE employee_id = 101;
The trigger executes:
UPDATE employees
SET first_name = 'Robert'
WHERE employee_id = 101;
9. Example of an INSTEAD OF DELETE trigger
CREATE OR REPLACE TRIGGER trg_emp_v_delete
INSTEAD OF DELETE ON emp_v
FOR EACH ROW
BEGIN
DELETE FROM employees
WHERE employee_id = :OLD.employee_id;
END;
/
Now:
DELETE FROM emp_v
WHERE employee_id = 101;
The trigger deletes the corresponding row from employees.
10. Can one INSTEAD OF trigger handle INSERT, UPDATE and DELETE?
Yes.
CREATE OR REPLACE TRIGGER trg_emp_v_dml
INSTEAD OF INSERT OR UPDATE OR DELETE ON emp_v
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO employees
(
employee_id,
first_name,
department_id
)
VALUES
(
:NEW.employee_id,
:NEW.first_name,
:NEW.department_id
);
ELSIF UPDATING THEN
UPDATE employees
SET
first_name = :NEW.first_name,
department_id = :NEW.department_id
WHERE employee_id = :OLD.employee_id;
ELSIF DELETING THEN
DELETE FROM employees
WHERE employee_id = :OLD.employee_id;
END IF;
END;
/
Oracle provides:
INSERTING
UPDATING
DELETING
to determine which operation caused the trigger to fire.
11. What is the most common use case?
One of the most important use cases is making a complex view appear updatable.
Suppose we have:
CREATE VIEW emp_dept_v AS
SELECT
e.employee_id,
e.first_name,
d.department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id;
The view contains data from:
EMPLOYEES
+
DEPARTMENTS
↓
EMP_DEPT_V
Suppose a user wants to execute:
INSERT INTO emp_dept_v
(
employee_id,
first_name,
department_name
)
VALUES
(
101,
'John',
'IT'
);
The trigger can translate this into operations on the underlying tables.
CREATE OR REPLACE TRIGGER trg_emp_dept_insert
INSTEAD OF INSERT ON emp_dept_v
FOR EACH ROW
DECLARE
v_department_id departments.department_id%TYPE;
BEGIN
SELECT department_id
INTO v_department_id
FROM departments
WHERE department_name = :NEW.department_name;
INSERT INTO employees
(
employee_id,
first_name,
department_id
)
VALUES
(
:NEW.employee_id,
:NEW.first_name,
v_department_id
);
END;
/
Now the view provides a convenient interface while the trigger handles the underlying tables.
12. Can an INSTEAD OF trigger modify multiple tables?
Yes.
This is one of its biggest advantages.
Suppose the view represents:
CUSTOMER
+
ADDRESS
+
ORDER
A single DML operation against the view can be translated by the trigger into:
INSERT CUSTOMER
↓
INSERT ADDRESS
↓
INSERT ORDER
Example:
CREATE OR REPLACE TRIGGER trg_order_v
INSTEAD OF INSERT ON order_v
FOR EACH ROW
BEGIN
INSERT INTO customers (...)
VALUES (...);
INSERT INTO addresses (...)
VALUES (...);
INSERT INTO orders (...)
VALUES (...);
END;
/
This is a common reason for using INSTEAD OF triggers.
13. Can an INSTEAD OF trigger use :OLD and :NEW together?
Yes, for an UPDATE.
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF UPDATE ON emp_v
FOR EACH ROW
BEGIN
UPDATE employees
SET
first_name = :NEW.first_name
WHERE employee_id = :OLD.employee_id;
END;
/
Here:
:OLD.employee_id
↓
identifies the old row
:NEW.first_name
↓
contains the new value
14. Can an INSTEAD OF trigger change :NEW?
You should think of INSTEAD OF triggers differently from BEFORE row triggers.
For an INSTEAD OF trigger, the trigger itself determines what happens to the underlying tables.
For example:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
INSERT INTO employees
(
employee_id,
first_name
)
VALUES
(
:NEW.employee_id,
UPPER(:NEW.first_name)
);
END;
/
Rather than changing the view's :NEW value, the trigger can directly control what is inserted into the base table.
15. What happens if the view has multiple underlying tables?
This is where INSTEAD OF triggers become especially useful.
Example view:
CREATE VIEW employee_department_v AS
SELECT
e.employee_id,
e.first_name,
d.department_id,
d.department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id;
An update like:
UPDATE employee_department_v
SET department_name = 'FINANCE'
WHERE employee_id = 101;
may not be directly updatable in the way you want.
An INSTEAD OF trigger can determine:
department_name
↓
find department_id
↓
update employees.department_id
Example:
CREATE OR REPLACE TRIGGER trg_emp_dept_update
INSTEAD OF UPDATE ON employee_department_v
FOR EACH ROW
DECLARE
v_department_id NUMBER;
BEGIN
SELECT department_id
INTO v_department_id
FROM departments
WHERE department_name = :NEW.department_name;
UPDATE employees
SET department_id = v_department_id
WHERE employee_id = :OLD.employee_id;
END;
/
16. Can an INSTEAD OF trigger be BEFORE or AFTER?
No.
These are different trigger timings:
BEFORE
AFTER
INSTEAD OF
You don't write:
BEFORE INSTEAD OF INSERT
or:
AFTER INSTEAD OF INSERT
Correct syntax:
INSTEAD OF INSERT ON view_name
17. Can an INSTEAD OF trigger be statement-level?
No.
This is a very common interview question.
INSTEAD OF triggers are row-level only.
Correct:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
...
END;
/
Incorrect:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
BEGIN
...
END;
/
18. Can an INSTEAD OF trigger be created on a table?
No.
For example:
CREATE OR REPLACE TRIGGER trg_emp
INSTEAD OF INSERT ON employees
FOR EACH ROW
BEGIN
...
END;
/
This is not valid because employees is a table.
Use:
BEFORE INSERT ON employees
or:
AFTER INSERT ON employees
19. Can an INSTEAD OF trigger perform validation?
Yes.
Example:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
IF :NEW.employee_id IS NULL THEN
RAISE_APPLICATION_ERROR(
-20001,
'Employee ID cannot be NULL'
);
END IF;
INSERT INTO employees
(
employee_id,
first_name
)
VALUES
(
:NEW.employee_id,
:NEW.first_name
);
END;
/
The trigger validates the input before performing the actual DML.
20. Can an INSTEAD OF trigger call a procedure?
Yes.
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
create_employee(
:NEW.employee_id,
:NEW.first_name
);
END;
/
Procedure:
CREATE OR REPLACE PROCEDURE create_employee
(
p_employee_id NUMBER,
p_first_name VARCHAR2
)
IS
BEGIN
INSERT INTO employees
(
employee_id,
first_name
)
VALUES
(
p_employee_id,
p_first_name
);
END;
/
This can keep complex trigger logic manageable.
21. Does the original DML execute after the INSTEAD OF trigger?
No.
That's the whole meaning of INSTEAD OF.
Suppose:
INSERT INTO emp_v
VALUES (101, 'John');
The flow is:
INSERT INTO emp_v
↓
INSTEAD OF trigger
↓
Trigger code executes
↓
INSERT into employees
↓
Original INSERT on view is NOT separately executed
INSTEAD OF = replace the requested operation with my trigger logic.
22. What happens if the INSTEAD OF trigger does nothing?
Suppose:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
NULL;
END;
/
Then:
INSERT INTO emp_v
VALUES (101, 'John');
The trigger fires, but no underlying insert happens.
So the requested operation effectively does nothing.
23. Can an INSTEAD OF trigger perform DML on the same view?
Be careful.
For example:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
INSERT INTO emp_v
VALUES (...);
END;
/
This can cause recursive trigger execution.
Conceptually:
INSERT into view
↓
INSTEAD OF trigger
↓
INSERT into same view
↓
INSTEAD OF trigger again
↓
...
This should generally be avoided.
The trigger should normally perform DML on the underlying base tables, not recursively on the same view.
24. Can an INSTEAD OF trigger perform COMMIT?
No.
For example:
CREATE OR REPLACE TRIGGER trg_emp_v
INSTEAD OF INSERT ON emp_v
FOR EACH ROW
BEGIN
INSERT INTO employees (...);
COMMIT;
END;
/
This is not allowed.
You generally cannot use transaction control such as:
COMMIT
ROLLBACK
inside a trigger.
25. What is the difference between BEFORE, AFTER, and INSTEAD OF?
| Trigger | Usually used on | Purpose |
|---|---|---|
BEFORE |
Table | Validate/modify before DML |
AFTER |
Table | Audit/log after DML |
INSTEAD OF |
View | Replace DML on a view |
For a table:
Table
↓
BEFORE INSERT
↓
Insert
↓
AFTER INSERT
For a view:
View
↓
INSERT
↓
INSTEAD OF trigger
↓
Your custom DML
↓
Base table(s)
26. What is a complete example with INSERT, UPDATE and DELETE?
Let's create two tables.
Departments
CREATE TABLE departments (
department_id NUMBER PRIMARY KEY,
department_name VARCHAR2(100)
);
Employees
CREATE TABLE employees (
employee_id NUMBER PRIMARY KEY,
first_name VARCHAR2(100),
department_id NUMBER REFERENCES departments(department_id)
);
Create a view:
CREATE OR REPLACE VIEW emp_dept_v AS
SELECT
e.employee_id,
e.first_name,
d.department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id;
Now create an INSTEAD OF trigger:
CREATE OR REPLACE TRIGGER trg_emp_dept_v
INSTEAD OF INSERT OR UPDATE OR DELETE ON emp_dept_v
FOR EACH ROW
DECLARE
v_department_id NUMBER;
BEGIN
IF INSERTING THEN
SELECT department_id
INTO v_department_id
FROM departments
WHERE department_name = :NEW.department_name;
INSERT INTO employees
(
employee_id,
first_name,
department_id
)
VALUES
(
:NEW.employee_id,
:NEW.first_name,
v_department_id
);
ELSIF UPDATING THEN
SELECT department_id
INTO v_department_id
FROM departments
WHERE department_name = :NEW.department_name;
UPDATE employees
SET
first_name = :NEW.first_name,
department_id = v_department_id
WHERE employee_id = :OLD.employee_id;
ELSIF DELETING THEN
DELETE FROM employees
WHERE employee_id = :OLD.employee_id;
END IF;
END;
/
Now users can work with:
INSERT INTO emp_dept_v
(
employee_id,
first_name,
department_name
)
VALUES
(
101,
'John',
'IT'
);
Instead of directly manipulating the underlying tables, the trigger translates the request.
27. What happens if 100 rows are affected?
Because an INSTEAD OF trigger is row-level:
DELETE FROM emp_dept_v;
If the view represents 100 affected rows:
DELETE statement
↓
100 rows
↓
INSTEAD OF trigger
↓
fires 100 times
This is an important distinction.
| Trigger type | Execution |
|---|---|
| Statement-level trigger | Once per statement |
| Row-level trigger | Once per affected row |
INSTEAD OF trigger |
Always row-level |
28. Common INSTEAD OF trigger interview traps
Trap 1
Question: Is an INSTEAD OF trigger row-level or statement-level?
Answer: ✅ Always row-level.
FOR EACH ROW
is required.
Trap 2
Question: Can it be created on a table?
Answer: ❌ No.
It is primarily used for views.
Trap 3
Question: Can it use :OLD and :NEW?
Answer: ✅ Yes.
Because it is row-level.
Trap 4
Question: Can it be BEFORE or AFTER?
Answer: ❌ No.
It is a separate trigger timing:
INSTEAD OF
Trap 5
Question: What does INSTEAD OF mean?
Answer:
Trap 6
Question: Can it update multiple base tables?
Answer: ✅ Yes.
This is one of its major use cases.
Trap 7
Question: Can it use :NEW during INSERT?
Answer: ✅ Yes.
Trap 8
Question: Can it use :OLD during DELETE?
Answer: ✅ Yes.
29. INSTEAD OF trigger cheat sheet
Memorize this:
| Feature | INSTEAD OF |
|---|---|
| Used on | VIEW |
| Used on table | ❌ No |
| Row-level | ✅ Always |
FOR EACH ROW |
✅ Required |
:OLD |
✅ Yes |
:NEW |
✅ Yes |
BEFORE |
❌ No |
AFTER |
❌ No |
INSERT |
✅ Yes |
UPDATE |
✅ Yes |
DELETE |
✅ Yes |
| Multiple base tables | ✅ Yes |
COMMIT |
❌ No |
⭐ The easiest way to remember
BEFORE → "Do something before DML."
AFTER → "Do something after DML."
INSTEAD OF → "Don't perform the requested view DML; I'll handle it."
And the key interview statement:
| Trigger | TABLE | VIEW |
|---|---|---|
BEFORE |
✅ | ❌ |
AFTER |
✅ | ❌ |
INSTEAD OF |
❌ | ✅ |
INSTEAD OF trigger↓
VIEW
↓
FOR EACH ROW↓
:OLD / :NEW available↓
Perform DML on underlying table(s)
INSTEAD OF trigger design.
No comments:
Post a Comment