En lösning du kan göra är att skapa en materialiserad vy som innehåller en fråga som identifierar de "dåliga raderna".
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);
Låt oss nu försöka infoga några rader:
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.
Det gick bra. Låt oss nu skicka ett meddelande till mig själv:
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
Redigera, mer förklaring: Ok, denna fråga (i den materialiserade vyns definition) identifierar och räknar alla meddelanden som skickas till en själv. Det vill säga alla rader som bryter mot regeln du angav.
select count(*) as bad_rows
from messages m
join receivers r using(message_id)
where m.sender_id = r.receiver_id;
Så frågan bör alltid returnera 0 rader, eller hur? Vad den materialiserade vyn gör är att uppdatera sig själv när någon utför en DML-operation mot tabellernas messages
eller receivers
. Så i teorin, om någon infogar ett meddelande till sig själv, skulle frågan returnera bad_rows = 1
. Men jag har också inkluderat en begränsning för den materialiserade vyn, och säger att det enda tillåtna värdet för kolumnen bad_rows
är 0. Oracle låter dig inte utföra någon transaktion som ger ett annat värde.
Så om du tittar på det andra paret av infogningssatser kan du se att jag har lyckats infoga den felaktiga raden i mottagare, men Oracle ger en begränsningsöverträdelse när jag försöker begå.