使用其他表中的子查询添加约束

时间:2014-03-06 07:12:28

标签: sql oracle oracle10g

我有两张桌子:

  1. MESSAGES ( ID(pk), SENDER )

  2. RECIEVERS ( ID references MESSAGE(ID), RECIEVER, pk(ID, RECIEVER) )

  3. 这是交易:

    1. 邮件只能有一个发件人。的完成

    2. 消息可以有多个接收者,但接收者不能多次接收相同的消息。的完成

    3. 发件人无法向自己发送消息。 我该如何做这部分?

    4. 我试过了:

      update table RECIEVERS add constraint "RECIEVERS_CK_SELF_SEND"
      ( RECIEVER not in
           ( select SENDER
              from MESSAGES
               where MESSAGE.ID=RECIEVER.ID));
      

      在Oracle数据库10g XE上,但是我收到以下错误:

        

      此处不允许进行子查询

1 个答案:

答案 0 :(得分:0)

您可以做的一个解决方法是创建一个包含标识“坏行”的查询的物化视图。

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行,对吧? 物化视图的作用是在任何人对表messagesreceivers提交DML操作时刷新自身。所以理论上,如果有人向自己插入消息,查询将返回bad_rows = 1。但是,我还在物化视图中包含了一个约束,表示列bad_rows唯一允许的值为0. Oracle不允许您提交任何给出其他值的事务。

因此,如果你查看第二对insert语句,你可以看到我设法在接收器中插入了错误的行,但是当我尝试提交时,Oracle会出现约束违规。