Is it bad practice to use triggers or scripts to maintain data integrity that Oracle is not designed to enforce, or is this a sign I’m modeling my data in a poor way?
From responses to a previous post (Implementing User Defined Fields), I have decided that I want to move forward designing with a mix of Class and Concrete Inheritance. I want one base class for all SAMPLE then a concrete table for each unique set of attributes.
While I can enforce that each concrete table has a parent entry in SAMPLE by making SAMPLE.sample_id the primary key with a foreign key constraint. However, I do not know how to enforce that a SAMPLE entry has exactly one child since the child entry could be in any number of tables.
How can I enforce this? If the solution is INSERT, UPDATE, and DELETE triggers, is this considered bad-practice?
I think you can solve this by using a materialized view that is a union all of TABLEA, TABLEB and TABLEC + groub by on master table id. You have to create a materialized view logs to make this a fast refreshable materialize view. And you have add a check constraint that throws an error when there is more than row in the materialized view per master table id.
Rob van Wijk explains here http://rwijk.blogspot.com/2009/07/fast-refreshable-materialized-view.html a lot about fast refresible mv’s. Rob van Wijk is often present here at stackoverflow too.
Here you can read on the use of check constraints on materialized views: http://technology.amis.nl/blog/475/introducing-materialized-views-as-mechanism-for-business-rule-implementation-complex-declarative-constraints
Using fast refresizable mv’s means that the integrity check is done during committing, not during the inserting or updateting of data.
I’m a very tired I can’t test it myself and I can’t provide a real example.
edit1: Here is the example:
It works when you create a fast refresh mv with a check constraint and a unique function based index.
First we create the tables:
Then we create the mv logs:
The mv (the umarker column is really needed!):
Now we add a check constraint to this mv to ensure that you can’t insert twice in the same detail table per master_id:
And we add a unique function based index to this mv to ensure that you can’t insert in table a and table b with the same master_id:
Test 1 (the happy path):
SQL> insert into mastertable values (1);
1 rij is aangemaakt.
SQL> insert into tablea values (1,1);
1 rij is aangemaakt.
SQL> commit;
Commit is voltooid.
Test 2 (one insert in table a and one insert in table b with same master_id)
SQL> insert into mastertable values (2);
1 rij is aangemaakt.
SQL> insert into tablea values (2,2);
1 rij is aangemaakt.
SQL> insert into tableb values (3,2);
1 rij is aangemaakt.
SQL> commit;
commit
*
FOUT in regel 1:
.ORA-12008: Fout in pad voor vernieuwen van snapshot.
ORA-00001: Schending van UNIQUE-beperking (TESTT.TABLE_ABC_UFBI1).
test 3 (insert in table a twice with same master_id)
SQL> insert into mastertable values (3);
1 rij is aangemaakt.
SQL> insert into tablea values (4,3);
1 rij is aangemaakt.
SQL> insert into tablea values (5,3);
1 rij is aangemaakt.
SQL> commit;
commit
*
FOUT in regel 1:
.ORA-12008: Fout in pad voor vernieuwen van snapshot.
ORA-02290: CHECK-beperking (TESTT.SYS_C0015406) is geschonden.