sql >> Databasteknik >  >> RDS >> Oracle

Lägga till begränsningar med hjälp av underfråga från annan tabell

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å.




  1. Datamodell för bilverkstad

  2. Med PHP subtrahera en kvantitet från en mysql-tabell

  3. MySQL - Visa alla permutationer?

  4. Hur lagrar man formaterad text i MySQL-tabellen?