Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Reddi.

Asked: May 13, 2001 - 1:12 pm UTC

Last updated: July 06, 2009 - 5:37 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Tom

I dont see the need for a check option with views. I work in forms, if I give my user only the columns which he needs to see from a view, how can he update columns which are not provided by the view.

Thanks

and Tom said...

You are missing the point of the check option. It prevents you from updating a row to become a value that is not in view anymore. Consider:

tkyte@TKYTE816> create table t ( x int );

Table created.

tkyte@TKYTE816>
tkyte@TKYTE816> create or replace view v1
2 as
3 select * from t where x > 0
4 /

View created.

tkyte@TKYTE816>
tkyte@TKYTE816>
tkyte@TKYTE816> create or replace view v2
2 as
3 select * from t where x > 0
4 with check option
5 /

View created.

tkyte@TKYTE816>
tkyte@TKYTE816> insert into v1 values ( -1 );

1 row created.

tkyte@TKYTE816> insert into v2 values ( -1 );
insert into v2 values ( -1 )
*
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation



it makes sure you only create data that matches the definition of the view, its another type of integrity constraint.



Rating

  (5 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks very much

Bong99, December 03, 2002 - 5:16 am UTC

It is what I want know, thanks

What about "with check option" applied to aggregate views?

Tom, July 11, 2005 - 7:01 pm UTC

Tom -

This is likely to be a dumb question, but here goes
anyway. How can I use a simple view definition that
includes a "with check option" clause and also a
"group by" aggregation? My desire is to limit the
sum of a quantity to a certain upper bound,
as shown here:

drop table t1;
create table t1
(name varchar2(10),
sales_commission number);

insert into t1 values ('Tom',12);
insert into t1 values ('Tom',25);
insert into t1 values ('Steve',40);

-- Write a view that collects the sales
-- commission for each of the individuals.
-- The limit is 100, but I cannot get it to work.
drop view v1;
create view v1 as
select name, sum(sales_commission) ssc
from t1
group by name
having sum(sales_commission) <= 100
with check option;

insert into t1 values ('Tom',63);
-- succeeds, as it should because the sum = 100
insert into t1 values ('Steve',63);
-- succeeds, but I'd rather that it didn't...

At this point, the v1 view simply shows the "Tom" name and
that's it. I'd love for the second insert
to violate the constraint on the view, but
I can't get it to go at all.

The dumb part of the question is this: If I
can't use the very elegant and easy "with check
constraint" option on my view, then what approach
would you recommend? I suppose that I could
take advantage of some before row triggers, but I
sense I'm missing something real easy here. Can
you help?

Thanks very much,
Tom G.

Tom Kyte
July 11, 2005 - 7:19 pm UTC

that'll not work -- you are not inserting into v1, but t1.

what is the primary key of t1? we can do this with materialized on commit refresh mv's


ps: no such thing as dumb questions of course, the only dumb thing is to sit on your hands and never ask them.

Okay. An MV will work, but is there a better way?

Tom, July 12, 2005 - 1:49 pm UTC

Tom -

Gotcha. After thinking about this a while and reading a
very, very applicable past thread of yours (</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:42304816945767 <code>,
this is real easy, as shown below by my new test case
that uses a base table with a primary key:

drop materialized view v1;

-- Recreate my table, being sure to add a column such
-- that a primary key can be defined. The "name" column
-- is not a suitable PK by itself because a single person
-- can have more than one sales commission.
drop table t1;
create table t1
(name varchar2(10),
sales_commission_seq number,
sales_commission number);

alter table t1 add primary key (name, sales_commission_seq);

create sequence my_seq;

insert into t1 values ('Tom',my_seq.nextval,40);
insert into t1 values ('Steve',my_seq.nextval,40);
insert into t1 values ('Tom',my_seq.nextval,40);
insert into t1 values ('Steve',my_seq.nextval,20);

create materialized view log on t1
with primary key including new values;

create materialized view v1
refresh complete on commit as
select name, sum(sales_commission) ssc
from t1
group by name;

alter table v1 add constraint sales_commission_chk
check (ssc <= 100);

-- Now, add a couple of rows, committing each time.
-- The first one will
-- succeed, but the second one should cause the
-- ORA-12008 error.
insert into t1 values ('Tom',my_seq.nextval,10);
commit;
insert into t1 values ('Steve',my_seq.nextval,50);
commit;

++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This is all fine and dandy, but is there an easy way to detect
"limit-breaking" inserts into my main table without
having to commit the changes first? I'd love for this
to operate similarly to the way a regular check constraint
on a regular table works.

Thanks so much for your fine work!

Tom

Tom Kyte
July 13, 2005 - 10:38 am UTC

Yes, using triggers and a "do it yourself rollup". it doesn't work perfectly unless you use deferrable constraints on the "rolled up" table since an insert into the base table of 50 rows will generate 50 single row updates to the roll up table.

</code> https://www.oracle.com/technetwork/issue-archive/2005/05-mar/o25asktom-089621.html <code>

you could maintain the rollup
it would have a deferrable constraint

you would insert into base table, and you can "set constraint <cname> immediate" after an insert to "validate" the data.




how about this

amit poddar, July 12, 2005 - 2:30 pm UTC

SQL> CREATE TABLE T1 (name varchar2(10),sales_commission NUMBER)
/  2  

Table created.

SQL> CREATE TABLE T1_SUM
  (  NAME VARCHAR2(10),
     SSC  NUMBER,
     SUM_CONS_VALUE NUMBER,
          CONSTRAINT T1_SUM_CHK CHECK (ssc < sum_cons_value) ENABLE
   ) 
/

  2    3    4    5    6    7  
Table created.

SQL> SQL> 
SQL> create or replace trigger t1_trg
before insert or update or delete
        on scott.t1
        referencing new as new old as old
        for each row
begin
   if ( INSERTING )
   then
      merge into t1_sum a
       using (select :new.name name,
                     :new.sales_commission comm
              from dual) b
       on (a.name = b.name)
       when matched then
          update set a.ssc = a.ssc + b.comm
       when not matched then
          insert (name,ssc,sum_cons_value) values (b.name,b.comm,100);
   elsif ( UPDATING )
   then
      update t1_sum a
         set a.ssc = a.ssc - :old.sales_commission
        where a.name = :old.name;

      merge into t1_sum a
      using (select :new.name name,
                    :new.sales_commission comm
              from dual) b
       on (a.name = b.name)
       when matched then
          update set a.ssc = a.ssc + b.comm
       when not matched then
          insert (name,ssc,sum_cons_value) values (b.name,b.comm,100);
   else
       update t1_sum a
          set a.ssc = a.ssc - :old.sales_commission;
   end if;
end;
/

Trigger created.

SQL> 


SQL> insert into t1 values ('Tom',100);
insert into t1 values ('Tom',100)
            *
ERROR at line 1:
ORA-02290: check constraint (SCOTT.T1_SUM_CHK) violated
ORA-06512: at "SCOTT.T1_TRG", line 4
ORA-04088: error during execution of trigger 'SCOTT.T1_TRG'


SQL> insert into t1 values ('Tom',50);

1 row created.

SQL> insert into t1 values ('Tom',35)
  2  /

1 row created.

SQL> insert into t1 values ('Tom',33);
insert into t1 values ('Tom',33)
            *
ERROR at line 1:
ORA-02290: check constraint (SCOTT.T1_SUM_CHK) violated
ORA-06512: at "SCOTT.T1_TRG", line 4
ORA-04088: error during execution of trigger 'SCOTT.T1_TRG'


SQL> insert into t1 values ('Amit',33);

1 row created.

SQL>                
SQL> update t1 set sales_commission =200 where name='Amit';
update t1 set sales_commission =200 where name='Amit'
       *
ERROR at line 1:
ORA-02290: check constraint (SCOTT.T1_SUM_CHK) violated
ORA-06512: at "SCOTT.T1_TRG", line 19
ORA-04088: error during execution of trigger 'SCOTT.T1_TRG'


 

Tom Kyte
July 13, 2005 - 10:42 am UTC

i believe the constraint should be deferrable to allow for multi-row updates/inserts to succeed when they should succeed.

with check option vs mutating table problem

Muhammet, June 28, 2009 - 2:55 am UTC

Hi Tom,
Some business requirements can be solved with trigger. But there can be also mutating table problem. Consider this : In hr schema in employees table I do not want any salary to be larger than two times of maximum salary. I can solve this problem with trigger . but I must handle mutating trigger problem with implementing packages. And also I must lock the whole employees table.
Another solution I found is using a updateble view with check option. In my problem like this

create or replace view emp_view
as
select *
from hr.employees
where salary < (select max(salary)
from hr.employees)*2
with check option;

I want to learn which is better in performance, locking mechanism and scalibility. View with check option or Trigger ?
thanks,
Tom Kyte
July 06, 2009 - 5:37 pm UTC

... Some business requirements can be solved with trigger. ...

but they shouldn't be...



your view situation requires locking the table as well - think about it please - it has nothing to do with a trigger versus a view, it has everything to do with MULTI-USER race conditions and the fact that you cannot see my changes until I commit.

suppose you have in the table:

EMPNO      SALARY
-------    ----------
1234       1000
5678        500



and I issue: update emp set salary = 400 where empno = 1234;

and you issue: update emp set salary = 1100 where empno = 5678;


Now, we do that at about the same time, what would your view do????? Oh, it would set empno 5678 to 1100 (ok, that is less than 2x1000), but at the same time it would downgrade the salary of 1234 from 1000 to 400. The new max salary if that transaction takes place is 1,000 - but you'll make it 1,1000.
My approach would be either


valid choices:

a) a materialized view with a deferred check constraint
b) a stored procedure (eg: NO INSERT/UPDATE/DELETE granted to applications, they are not smart enough to do this correctly) that does the right thing and is multi-user safe.


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library