Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Re: an ON-COMMIT trigger desperately needed

Re: an ON-COMMIT trigger desperately needed

From: <garpinc_at_my-deja.com>
Date: 2000/07/06
Message-ID: <8k2nvc$e0p$1@nnrp1.deja.com>

I use developer 2000 to access a database back end so using object tables with nested table of records seems to be not an option. The idea to have another table with deferred check constraints is a cool one except that it still is not sufficient when it comes to more complicated examples like we are trying to overcome.

For instance it might not be only the number of rows in a child table that matter. In many situations depending on the type of the master record, certain fields in the child records are required and in addition there must be at least one row in the particular child table.

This makes the additional table and related check constraint and triggers on child tables quite complicated. In addition if there are a large number of rows in the master table as in our case then there is an additional equal number of rows in this additional table which leads to significant space loss since the data is really only relavent at the time of the transaction commit. One other drawback is that for each insert, update and delete I have to incur the performance overhead of an insert, update or delete into this table.

Back to the ultimate solution.
Is it possible that for tables with the key that I am interested in I can put a trigger that inserts rows into a package table of records with a list of the key values (eliminating duplicates). And then every time some application fires a commit or a check constraints then
1) a procedure fires
2) it traverses the table of records passing the key values as a

   parameter to a procedure that reads the master rows and validates    the surrounding tables
3) if the validation succeeds then transaction rolls back

>
> Your example I believe was a deferred RI constraint.
> An example of a real world example would be:
> I have a table called CAR and a table called PARTS
> a car must have 4 wheels and a car must have a steering wheel.
> I want to make sure that no user other than the user actually doing
 the
> inserts can see a partial car in the database. (i.e. defered
 validation)
> At commit time if car does not have 4 wheels and a steering wheel
> transaction must error out and rollback.
> (similar to what happens below however the validation here is to
> select count(*) from PARTS where part type = wheel
> and if count != 4 then rollback
> and similar for sterring wheel)
>

I agree -- it would be functionality people would use, however.....

In this case, I would use an Oracle object type and create a complex object
type CAR with a nested table|varray type of parts (or perhaps tires). for
example:

ops$tkyte_at_8i> create or replace type parts_array as table of varchar2 (25)
  2 /
Type created.

ops$tkyte_at_8i> create or replace type car as object

  2  (       vin                     number,
  3          parts           parts_array
  4 )
  5 /
Type created.

ops$tkyte_at_8i> create table cars of car nested table parts store as car_parts;
Table created.

ops$tkyte_at_8i> create or replace trigger car_trigger   2 after insert on cars for each row
  3 declare
  4 cnt number default 0;
  5 begin

  6          for i in 1 .. :new.parts.count loop
  7                  if :new.parts(i) = 'wheel' then
  8                          cnt := cnt+1;
  9                  end if;
 10          end loop;
 11          if (cnt<>4) then
 12                  raise_application_error( -20001, 'must have four
wheels' );
 13          end if;

 14 end;
 15 /
Trigger created.

ops$tkyte_at_8i> insert into cars values ( car( 1234, parts_array( 'wheel', 'wheel', 'wheel', 'wheel' ) ) );
1 row created.

ops$tkyte_at_8i> insert into cars values ( car( 4321, parts_array( 'wheel', 'wheel', 'wheel' ) ) );
insert into cars values ( car( 4321, parts_array( 'wheel', 'wheel', 'wheel' ) ) )

            *
ERROR at line 1:

ORA-20001: must have four wheels
ORA-06512: at "OPS$TKYTE.CAR_TRIGGER", line 10
ORA-04088: error during execution of trigger 'OPS$TKYTE.CAR_TRIGGER

If I did not want to use object tables -- I would still use object TYPES and
create an object view on my relational tables and use INSTEAD OF triggers on
the view to:

o validate
o insert/update the base relational tables...

In this case, I assemble the car in one "row" if you will and can use a conventional trigger. The client works with the "car", the database works
with a "row" -- the row is really a complex set of rows in many tables....

If I had to do this relationally -- knowing then need 4 tires, I have four
columns - each of which is NOT NULL (deferrable if I want it). I would just
store the data as it should be in a "relational" model.

If I had to do this in a "cars" and "parts" table -- I would maintain another table off to the side. It would be my "validation" table.

for example:

ops$tkyte_at_8i>
ops$tkyte_at_8i> create table cars ( vin number primary key );

Table created.

ops$tkyte_at_8i>
ops$tkyte_at_8i> create table parts ( vin number references cars, partname varchar2(25) );

Table created.

ops$tkyte_at_8i>
ops$tkyte_at_8i> create table cars_parts_cnt   2 ( vin number,
  3 partname varchar2(25),
  4 cnt number,
  5 constraint check_cnts check
  6 ( ( partname = 'wheels' and cnt = 4 ) or   7 ( partname <> 'wheels' )
  8 ) initially deferred
  9 )
 10 /

Table created.

ops$tkyte_at_8i>
ops$tkyte_at_8i> create or replace trigger t   2 after insert or update or delete on parts   3 for each row
  4 begin

  5      if (updating or inserting)
  6      then
  7          update cars_parts_cnt
  8             set cnt=cnt+1
  9           where vin = :new.vin
 10             and partname=:new.partname;
 11
 12          if (sql%rowcount=0) then
 13              insert into cars_parts_cnt
values(:new.vin,:new.partname,1);
 14          end if;
 15      end if;
 16
 17      if (updating or deleting)
 18      then
 19          update cars_parts_cnt
 20             set cnt=cnt-1
 21           where vin = :old.vin
 22             and partname=:old.partname;
 23      end if;

 24 end;
 25 /

Trigger created.

ops$tkyte_at_8i>
ops$tkyte_at_8i>
ops$tkyte_at_8i> insert into cars values ( 1234 );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 1234, 'wheels' );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 1234, 'wheels' );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 1234, 'wheels' );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 1234, 'wheels' );

1 row created.

ops$tkyte_at_8i> commit;

Commit complete.

ops$tkyte_at_8i> insert into cars values ( 4321 );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 4321, 'wheels' );

1 row created.

ops$tkyte_at_8i> insert into parts values ( 4321, 'wheels' );

1 row created.

ops$tkyte_at_8i> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint (OPS$TKYTE.CHECK_CNTS) violated

>

Sent via Deja.com http://www.deja.com/
Before you buy. Received on Thu Jul 06 2000 - 00:00:00 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US