A foreign key guarantees that every child row points to an existing parent. That raises a question the moment someone deletes a parent: what happens to its children? Oracle offers three answers. By default the delete is refused; ON DELETE CASCADE deletes the children too; ON DELETE SET NULL keeps them and clears their reference.
Code for This Guide
The main examples are in the examples/tables folder of the Oracle Database 26ai code repository on GitHub, each with its output. They use NIMBUS, the sample schema of a fictional airline, which you can install with the scripts in the setup/nimbus folder.
They come from Oracle Database 26ai SQL and PL/SQL Book.
Syntax
column type references parent_table [(column)] [on delete {cascade | set null}]
constraint name foreign key (column) references parent_table (column)
[on delete {cascade | set null}]| Action | Deleting a parent with children |
|---|---|
| None (the default) | Fails with ORA-02292 |
| ON DELETE CASCADE | Deletes the children with the parent |
| ON DELETE SET NULL | Keeps the children and sets their foreign key to NULL |
The Default: Refuse
Example:
-- without a delete action, a parent with children cannot be deleted delete from routes where route_id = 1;
Output:
Error starting at line : 2 In command - delete from routes where route_id = 1 Error report - ORA-02292: integrity constraint (NIMBUS.FLIGHTS_ROUTE_FK) violated - child record found
Route 1 has flights, so it cannot be deleted while FLIGHTS references it.
ON DELETE CASCADE
The cascade example uses a FARE_RULES table, created first:
Example:
create table fare_rules (
rule_id number constraint fare_rules_pk primary key,
route_id number not null constraint fare_rules_route_fk references routes,
cabin varchar2(8) default 'ECONOMY' not null,
valid_from date not null,
valid_to date,
base_fare number(8,2) not null,
refundable boolean default false,
notes varchar2(200),
constraint fare_rules_cabin_ck check (cabin in ('BUSINESS', 'ECONOMY')),
constraint fare_rules_dates_ck check (valid_to is null or valid_to > valid_from),
constraint fare_rules_uk unique (route_id, cabin, valid_from)
);
insert into fare_rules (rule_id, route_id, valid_from, base_fare)
values (1, 1, date '2026-04-01', 520);
select rule_id, route_id, cabin, valid_from, base_fare, refundable from fare_rules;Output:
Table FARE_RULES created.
1 row inserted.
RULE_ID ROUTE_ID CABIN VALID_FROM BASE_FARE REFUNDABLE
__________ ___________ __________ ______________ ____________ _____________
1 1 ECONOMY 01-APR-2026 520 falseNotes that belong to a fare rule are deleted with it.
Example:
create table rule_notes ( note_id number primary key, rule_id number constraint rule_notes_rule_fk references fare_rules on delete cascade, note varchar2(100) ); insert into rule_notes values (1, 1, 'Winter promotion'), (2, 1, 'Excludes holidays'); delete from fare_rules where rule_id = 1; select count(*) as notes_left from rule_notes; rollback;
Output:
Table RULE_NOTES created.
2 rows inserted.
1 row deleted.
NOTES_LEFT
_____________
0
Rollback complete.Deleting the rule deletes both notes; the ROLLBACK undoes it all.
ON DELETE SET NULL
Example:
delete from notes_parent where id = 1; select id, parent_id from notes_child; rollback;
Output:
1 row deleted. ID PARENT_ID _____ ____________ 10 Rollback complete.
The child row stays, with its parent_id cleared. The foreign key column must allow NULLs for this action.
Things to Know
- Index foreign key columns: without an index, deleting a parent row locks the whole child table while Oracle checks for children.
- Cascades can chain through several levels of tables, which makes a single DELETE remove far more than it seems; use CASCADE only where children truly belong to the parent.
- Oracle has no ON UPDATE CASCADE; primary keys should not change, which is one reason to use surrogate keys.
Related Guides
Conclusion
A foreign key's ON DELETE action decides what happens to child rows when their parent is deleted: refuse by default, delete them with CASCADE, or clear their reference with SET NULL. Choose by whether the children can exist on their own, and index the foreign key columns.
See my articles more often when you search Google.
