sql >> Databáze >  >> RDS >> Oracle

Přidání omezení pomocí poddotazu z jiné tabulky

Jedním z řešení, které můžete udělat, je vytvořit materializovaný pohled obsahující dotaz identifikující „špatné řádky“.

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);

Nyní zkusme vložit nějaké řádky:

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.

To šlo dobře. Nyní mi pošleme zprávu:

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

Upravit, další vysvětlení: Dobře, tento dotaz (v definici materializovaného pohledu) identifikuje a počítá všechny zprávy, které jsou odesílány jemu samému. Tedy všechny řádky, které porušují pravidlo, které jste uvedl.

select count(*) as bad_rows 
  from messages  m
  join receivers r using(message_id)
 where m.sender_id = r.receiver_id;

Takže dotaz by měl vždy vracet 0 řádků, že? Co dělá materializovaný pohled, je obnovovat se, když někdo provede operaci DML proti tabulkám messages nebo receivers . Takže teoreticky, pokud někdo vloží zprávu pro sebe, dotaz vrátí bad_rows = 1 . Zahrnul jsem však také omezení pro materializované zobrazení, které říká, že jediná povolená hodnota pro sloupec bad_rows je 0. Oracle vám nedovolí provést žádnou transakci, která dává jinou hodnotu.

Takže když se podíváte na druhý pár příkazů insert, můžete vidět, že se mi podařilo vložit chybný řádek do přijímačů, ale když se pokusím zavázat, Oracle dává porušení omezení.




  1. Zámek a transakce v postgresu, které by měly zablokovat dotaz

  2. Převod databáze Postgresql z SQL_ASCII obsahující smíšené typy kódování na UTF-8

  3. MAX (sloupec) mi vrací špatnou hodnotu

  4. Vysvětlení SQL Server (localdb)\v11.0