Uma solução alternativa que você pode fazer é criar uma visualização materializada contendo uma consulta identificando as "linhas inválidas".
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);
Agora vamos tentar inserir algumas linhas:
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.
Correu bem. Agora vamos enviar uma mensagem para mim mesmo:
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
Editar, mais explicações: Ok, esta consulta (na definição da visão materializada), identifica e conta todas as mensagens que estão sendo enviadas para si mesmo. Ou seja, todas as linhas que violam a regra que você indicou.
select count(*) as bad_rows
from messages m
join receivers r using(message_id)
where m.sender_id = r.receiver_id;
Portanto, a consulta deve retornar 0 linhas o tempo todo, certo? O que a visualização materializada faz é se atualizar quando alguém confirma uma operação DML nas tabelas
messages
ou receivers
. Então, em teoria, se alguém inserir uma mensagem para si mesma, a consulta retornará bad_rows = 1
. Mas também incluí uma restrição na visualização materializada, dizendo que o único valor permitido para a coluna bad_rows
é 0. O Oracle não permitirá que você confirme nenhuma transação que dê outro valor. Portanto, se você observar o segundo par de instruções de inserção, poderá ver que consegui inserir a linha errada nos receptores, mas o Oracle fornece uma violação de restrição quando tento confirmar.