sql >> Database teknologi >  >> RDS >> Oracle

Tilføjelse af begrænsninger ved hjælp af underforespørgsel fra anden tabel

En løsning, du kan gøre, er at oprette en materialiseret visning, der indeholder en forespørgsel, der identificerer de "dårlige rækker".

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

Lad os nu prøve at indsætte nogle rækker:

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 gik godt. Lad os nu sende en besked til mig selv:

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

Rediger, mere forklaring: Ok, denne forespørgsel (i den materialiserede visningsdefinition) identificerer og tæller alle de beskeder, der bliver sendt til en selv. Det vil sige alle de rækker, der overtræder den regel du har angivet.

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

Så forespørgslen burde altid returnere 0 rækker, ikke? Hvad den materialiserede visning gør, er at opdatere sig selv, når nogen foretager en DML-operation mod tabellernes messages eller receivers . Så i teorien, hvis nogen indsætter en besked til sig selv, ville forespørgslen returnere bad_rows = 1 . Men jeg har også inkluderet en begrænsning på den materialiserede visning, idet jeg siger, at den eneste tilladte værdi for kolonnen bad_rows er 0. Oracle vil ikke lade dig begå nogen transaktion, der giver en anden værdi.

Så hvis du ser på det andet par insert-udsagn, kan du se, at det er lykkedes mig at indsætte den fejlagtige række i modtagere, men Oracle giver en overtrædelse af begrænsningen, når jeg forsøger at begå.




  1. Hvordan indsætter/opretter man lagrede procedurer i mySQL fra PHP?

  2. Hvordan forespørger jeg mellem to tidsintervaller ved hjælp af MySQL?

  3. Hentning af de mest almindelige søgeord fra en tsvector-kolonne

  4. Hvad er forskellen mellem en primærnøgle og en surrogatnøgle?