How to Use WITH CHECK OPTION on Oracle Views

Stop inserts and updates through a view from producing rows the view cannot see, make views read-only, and update through join views.

A view that shows a subset of rows, such as the sales department's employees, can be used to insert and update rows of its base table. Without a safeguard, an UPDATE through the view can move a row out of the subset, or an INSERT can add a row the view will never show. WITH CHECK OPTION forbids both, and WITH READ ONLY forbids changes through the view altogether.

Code for This Guide

The main examples are in the examples/views 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

create [or replace] view view as subquery
  [with check option [constraint name] | with read only]

With CHECK OPTION, every INSERT and UPDATE through the view must produce rows that satisfy the view's WHERE clause.

Updates That Leave the View

The view shows department 40. Raising a salary through it works; moving an employee to department 50 through it fails.

Example:

create or replace view sales_staff as
select employee_id, first_name, last_name, department_id, salary
from   employees
where  department_id = 40
with check option constraint sales_staff_ck;

update sales_staff set salary = salary + 100 where employee_id = 154;
update sales_staff set department_id = 50 where employee_id = 154;
rollback;

Output:

View SALES_STAFF created.

1 row updated.

Error starting at line : 8
In command -
update sales_staff set department_id = 50 where employee_id = 154
Error at Command Line : 8 Column : 8
Error report -
SQL Error: ORA-01402: view WITH CHECK OPTION where-clause violation

Rollback complete.

The second UPDATE would make the row invisible to the view, so it raises ORA-01402.

Inserts That Do Not Belong

The same rule applies to INSERT: a new row for department 50 cannot be added through the department 40 view.

Example:

-- an INSERT through the view must also produce a row the view can see
insert into sales_staff2 (employee_id, first_name, last_name, department_id, salary, email, hire_date, job_title, base_airport)
values (999, 'Test', 'Person', 50, 5000, 'test.person@nimbus.example', sysdate, 'Analyst', 'DXB');

Output:

Error starting at line : 2
In command -
insert into sales_staff2 (employee_id, first_name, last_name, department_id, salary, email, hire_date, job_title, base_airport)
values (999, 'Test', 'Person', 50, 5000, 'test.person@nimbus.example', sysdate, 'Analyst', 'DXB')
Error at Command Line : 2 Column : 13
Error report -
SQL Error: ORA-01402: view WITH CHECK OPTION where-clause violation

The view for this example was created like the previous one, with the columns needed for an insert, and dropped afterward.

WITH READ ONLY

A view meant for reporting only can forbid all DML.

Example:

create or replace view public_fares as
select route_id, cabin, round(avg(fare)) as typical_fare
from   tickets join flights using (flight_id)
group  by route_id, cabin
with read only;

delete from public_fares;

Output:

View PUBLIC_FARES created.

Error starting at line : 7
In command -
delete from public_fares
Error at Command Line : 7 Column : 13
Error report -
SQL Error: ORA-01732: data manipulation operation not legal on this view

The DELETE fails with ORA-01732. A view with aggregates such as this one could not be changed anyway, but WITH READ ONLY states the intention for any view.

Updatable Join Views

DML on a view changes its base tables. For a view with a join, Oracle reports which columns can be changed in USER_UPDATABLE_COLUMNS, based on which tables are key-preserved: tables whose primary key stays unique in the view's result. The example uses this view, created first:

Example:

create or replace view flight_board as
select f.flight_id, f.flight_no, r.origin, r.destination,
       f.scheduled_departure, f.status
from   flights f
join   routes r on r.route_id = f.route_id;

select flight_no, origin, destination, to_char(scheduled_departure, 'DD-MON') as day, status
from   flight_board
where  origin = 'SYD'
fetch  first 3 rows only;

Output:

View FLIGHT_BOARD created.

FLIGHT_NO    ORIGIN    DESTINATION    DAY       STATUS
____________ _________ ______________ _________ __________
NM149        SYD       AKL            11-JAN    ARRIVED
NM149        SYD       AKL            13-JAN    ARRIVED
NM149        SYD       AKL            01-JAN    ARRIVED

Example:

update flight_board set status = 'CANCELLED' where flight_id = 2800;

select column_name, updatable, insertable, deletable
from   user_updatable_columns
where  table_name = 'FLIGHT_BOARD'
order  by column_name;
rollback;

Output:

1 row updated.

COLUMN_NAME            UPDATABLE    INSERTABLE    DELETABLE
______________________ ____________ _____________ ____________
DESTINATION            NO           NO            NO
FLIGHT_ID              YES          YES           YES
FLIGHT_NO              YES          YES           YES
ORIGIN                 NO           NO            NO
SCHEDULED_DEPARTURE    YES          YES           YES
STATUS                 YES          YES           YES

6 rows selected.

Rollback complete.

Each flight appears once in the view, so FLIGHTS is key-preserved and its columns are updatable; a route appears once per flight, so the ROUTES columns are reported as not updatable. Check this view before relying on DML through a join view, and use an INSTEAD OF trigger for the rest.

Related Guides

Conclusion

WITH CHECK OPTION keeps INSERT and UPDATE through a view within the view's own rows, raising ORA-01402 otherwise, and WITH READ ONLY forbids DML through the view. For join views, USER_UPDATABLE_COLUMNS shows which base table columns can be changed.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted