Oracle
 sql >> база данни >  >> RDS >> Oracle

Добавяне на ограничения чрез подзаявка от друга таблица

Едно решение, което можете да направите, е да създадете материализиран изглед, съдържащ заявка, идентифицираща „лошите редове“.

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

Сега нека се опитаме да вмъкнем няколко реда:

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.

Това мина добре. Сега нека изпратим съобщение до себе си:

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

Редактиране, повече обяснение: Добре, тази заявка (в дефиницията на материализирания изглед) идентифицира и брои всички съобщения, които се изпращат до себе си. Тоест всички редове, които нарушават правилото, което посочихте.

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

Така че заявката трябва да връща 0 реда по всяко време, нали? Това, което прави материализираният изглед, е да се опреснява, когато някой извърши DML операция срещу таблиците messages или receivers . Така че на теория, ако някой вмъкне съобщение до себе си, заявката ще върне bad_rows = 1 . Но също така включих ограничение върху материализирания изглед, като казах, че единствената позволена стойност за колона bad_rows е 0. Oracle няма да ви позволи да извършите транзакция, която дава друга стойност.

Така че, ако погледнете втората двойка изрази за вмъкване, можете да видите, че успях да вмъкна грешния ред в приемници, но Oracle дава нарушение на ограничението, когато се опитам да се ангажирам.




  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 тригери - проблем с мутиращи таблици

  2. Какво точно означава trunc(date, 'IW')?

  3. SQL Multiple Вмъкване в няколко реда

  4. SELECT заявка с литерални знаци (двоеточие, точка и запетая) в Oracle

  5. Използване на Dapper с Oracle