Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Dodawanie ograniczeń za pomocą podzapytania z innej tabeli

Jednym z obejść, które możesz zrobić, jest utworzenie zmaterializowanego widoku zawierającego zapytanie identyfikujące „złe wiersze”.

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

Teraz spróbujmy wstawić kilka wierszy:

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 poszło dobrze. Teraz wyślijmy wiadomość do mnie:

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

Edytuj, więcej wyjaśnień: Ok, to zapytanie (w definicji widoku zmaterializowanego) identyfikuje i zlicza wszystkie wiadomości, które są do nas wysyłane. To znaczy wszystkie wiersze, które naruszają zasada, którą podałeś.

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

Zatem zapytanie powinno zawsze zwracać 0 wierszy, prawda? Widok zmaterializowany odświeża się, gdy ktoś zatwierdzi operację DML na tabelach messages lub receivers . Więc teoretycznie, jeśli ktoś wstawi do siebie wiadomość, zapytanie zwróci bad_rows = 1 . Ale dodałem również ograniczenie na widok zmaterializowany, mówiąc, że jedyna dozwolona wartość dla kolumny bad_rows wynosi 0. Oracle nie pozwoli na dokonanie transakcji, która daje inną wartość.

Więc jeśli spojrzysz na drugą parę instrukcji INSERT, zobaczysz, że udało mi się wstawić błędny wiersz do odbiorników, ale Oracle narusza ograniczenia, gdy próbuję zatwierdzić.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. używając pl/sql jak otworzyć katalog?

  2. Rekordy wstawione do mojej tabeli przez klienta SQL nie wyświetlają się, gdy są używane w programie jdbc

  3. JdbcPagingItemReader w partiach Spring nie daje poprawnych wyników

  4. Baza danych DB2 w programie Oracle SQL Developer

  5. regexp_substr pomija puste pozycje