Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Menambahkan batasan menggunakan subquery dari tabel lain

Satu solusi yang dapat Anda lakukan adalah membuat tampilan terwujud yang berisi kueri yang mengidentifikasi "baris buruk".

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

Sekarang mari kita coba menyisipkan beberapa baris:

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.

Itu berjalan dengan baik. Sekarang mari kita mengirim pesan ke diri saya sendiri:

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

Edit, penjelasan lebih lanjut: Oke, kueri ini (dalam definisi tampilan terwujud), mengidentifikasi dan menghitung semua pesan yang dikirim ke diri sendiri. Artinya, semua baris yang melanggar aturan yang Anda nyatakan.

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

Jadi kueri harus mengembalikan 0 baris setiap saat, bukan? Apa yang dilakukan tampilan terwujud, adalah untuk menyegarkan dirinya sendiri ketika seseorang melakukan operasi DML terhadap tabel messages atau receivers . Jadi secara teori, jika seseorang menyisipkan pesan ke dirinya sendiri, kueri akan mengembalikan bad_rows = 1 . Tapi, saya juga menyertakan batasan pada tampilan terwujud, dengan mengatakan bahwa satu-satunya nilai yang diizinkan untuk kolom bad_rows adalah 0. Oracle tidak akan mengizinkan Anda melakukan transaksi apa pun yang memberikan nilai lain.

Jadi jika Anda melihat pasangan kedua dari pernyataan penyisipan, Anda dapat melihat bahwa saya telah berhasil memasukkan baris yang salah di penerima, tetapi Oracle memberikan pelanggaran kendala ketika saya mencoba untuk melakukan.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle TO_DATE dengan hanya input waktu akan menambahkan komponen tanggal berdasarkan logika apa?

  2. oci_bind_by_name dan to_date PHP/OCI/Oracle

  3. SQL Query dengan CASE dan grup menurut

  4. dapatkan kolom huruf kecil dari ResultSet menggunakan nama kolom

  5. Pernyataan pembaruan Oracle dengan fungsi grup