ORA-04073: Column List Not Valid for This Trigger Type
ORA-04073 is a compile-time Oracle error that occurs when you specify a column list (OF column_name) in a trigger definition where it is not permitted. The OF clause is exclusively valid for UPDATE triggers in Oracle DML triggers, and using it with INSERT, DELETE, or INSTEAD OF triggers immediately raises this error.
Top 3 Causes
1. Using OF Clause with INSERT or DELETE Triggers
The most common cause is attaching OF column_name to an INSERT or DELETE event. Oracle's syntax strictly reserves the OF clause for UPDATE triggers only.
Incorrect (causes ORA-04073):
CREATE OR REPLACE TRIGGER trg_bad_insert
BEFORE INSERT OF salary ON employees
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('Salary: ' || :NEW.salary);
END;
/
Fixed:
CREATE OR REPLACE TRIGGER trg_good_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('New Salary: ' || :NEW.salary);
END;
/
2. Misplacing OF in Compound Event Triggers
When combining multiple DML events (INSERT, UPDATE, DELETE), developers sometimes incorrectly append the OF clause to the entire event list instead of only to the UPDATE keyword.
Incorrect (causes ORA-04073):
CREATE OR REPLACE TRIGGER trg_bad_compound
BEFORE INSERT OR UPDATE OR DELETE OF salary ON employees
FOR EACH ROW
BEGIN
NULL;
END;
/
Fixed — use UPDATING('column') inside the body instead:
CREATE OR REPLACE TRIGGER trg_good_compound
BEFORE INSERT OR UPDATE OR DELETE ON employees
FOR EACH ROW
BEGIN
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('Row inserted.');
ELSIF UPDATING('SALARY') THEN
DBMS_OUTPUT.PUT_LINE('Salary changed: ' || :OLD.salary || ' -> ' || :NEW.salary);
ELSIF DELETING THEN
DBMS_OUTPUT.PUT_LINE('Row deleted.');
END IF;
END;
/
3. Using OF Clause in INSTEAD OF Triggers
INSTEAD OF triggers, used on views, do not support the OF column_name clause at all. Any attempt to include it will immediately raise ORA-04073.
Incorrect (causes ORA-04073):
CREATE OR REPLACE TRIGGER trg_bad_instead
INSTEAD OF UPDATE OF salary ON emp_view
FOR EACH ROW
BEGIN
UPDATE employees SET salary = :NEW.salary
WHERE employee_id = :OLD.employee_id;
END;
/
Fixed:
CREATE OR REPLACE TRIGGER trg_good_instead
INSTEAD OF UPDATE ON emp_view
FOR EACH ROW
BEGIN
IF UPDATING('SALARY') THEN
UPDATE employees
SET salary = :NEW.salary
WHERE employee_id = :OLD.employee_id;
END IF;
END;
/
Quick Fix Summary
| Trigger Type |
OF Clause Allowed? |
Recommended Alternative |
|---|---|---|
INSERT |
❌ No | Use :NEW.column in body |
DELETE |
❌ No | Use :OLD.column in body |
UPDATE |
✅ Yes | UPDATE OF col ON table |
INSTEAD OF |
❌ No | Use UPDATING('col') in body |
| Compound Events | ⚠️ UPDATE only | Use UPDATING('col') function |
Prevention Tips
1. Standardize trigger templates in your team
Always define a standard trigger DDL template that includes a comment noting that OF column_list is only valid for UPDATE triggers. Validate all trigger DDL in a development environment before deploying to production.
2. Prefer UPDATING('column_name') over the OF clause
Make it a team coding standard to use the UPDATING(), INSERTING, and DELETING conditional predicates inside the trigger body rather than relying on the OF clause. This approach works universally across all trigger types and eliminates the risk of ORA-04073 entirely while keeping your trigger logic more readable and maintainable.
-- Preferred pattern: column-level check inside trigger body
CREATE OR REPLACE TRIGGER trg_best_practice
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
IF UPDATING('SALARY') THEN
-- handle salary change
:NEW.last_updated := SYSDATE;
END IF;
END;
/
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)