Una soluzione alternativa che puoi fare è creare una vista materializzata contenente una query che identifica le "righe non valide".
create table messages(
message_id number not null
,sender_id varchar2(20) not null
,primary key(message_id)
);
create table receivers(
message_id number not null
,receiver_id varchar2(20) not null
,primary key(message_id,receiver_id)
,foreign key(message_id) references messages(message_id)
);
create materialized view log
on receivers with primary key, rowid including new values;
create materialized view log
on messages with primary key, rowid (sender_id) including new values;
create materialized view mv
refresh fast on commit
as
select count(*) as bad_rows
from messages m
join receivers r using(message_id)
where m.sender_id = r.receiver_id;
alter materialized view mv
add constraint dont_send_to_self check(bad_rows = 0);
Ora proviamo a inserire alcune righe:
SQL> insert into messages(message_id, sender_id) values(1, 'Ronnie');
1 row created.
SQL> insert into receivers(message_id, receiver_id) values(1, 'Mayank Sharma');
1 row created.
SQL> commit;
Commit complete.
È andata bene. Ora mandiamo un messaggio a me stesso:
SQL> insert into messages(message_id, sender_id) values(2, 'Ronnie');
1 row created.
SQL> insert into receivers(message_id, receiver_id) values(2, 'Ronnie');
1 row created.
SQL> commit;
commit
*
ERROR at line 1:
ORA-12008: error in materialized view refresh path
ORA-02290: check constraint (RNBN.DONT_SEND_TO_SELF) violated
Modifica, ulteriori spiegazioni: Ok, questa query (nella definizione della vista materializzata), identifica e conta tutti i messaggi che vengono inviati a se stessi. Ovvero, tutte le righe che violano la regola che hai indicato.
select count(*) as bad_rows
from messages m
join receivers r using(message_id)
where m.sender_id = r.receiver_id;
Quindi la query dovrebbe restituire 0 righe in ogni momento, giusto? Ciò che fa la vista materializzata è aggiornarsi quando qualcuno esegue un'operazione DML sulle tabelle messages
o receivers
. Quindi, in teoria, se qualcuno inserisce un messaggio a se stesso, la query restituirebbe bad_rows = 1
. Ma ho anche incluso un vincolo sulla vista materializzata, dicendo che l'unico valore consentito per la colonna bad_rows
è 0. Oracle non ti consentirà di eseguire alcuna transazione che dia un altro valore.
Quindi, se guardi la seconda coppia di istruzioni di inserimento, puoi vedere che sono riuscito a inserire la riga errata nei ricevitori, ma Oracle fornisce una violazione del vincolo quando provo a eseguire il commit.