sql >> データベース >  >> RDS >> Oracle

他のテーブルからのサブクエリを使用して制約を追加する

    実行できる回避策の1つは、「不良行」を識別するクエリを含むマテリアライズドビューを作成することです。

    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
    

    編集、詳細説明: OK、このクエリ(マテリアライズドビュー定義内)は、自分に送信されているすべてのメッセージを識別してカウントします。つまり、違反するすべての行 あなたが述べたルール。

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

    したがって、クエリは常に0行を返す必要がありますか?マテリアライズドビューが行うことは、誰かがテーブルのmessagesに対してDML操作をコミットしたときに、それ自体を更新することです。 またはreceivers 。したがって、理論的には、誰かが自分自身にメッセージを挿入すると、クエリはbad_rows = 1を返します。 。ただし、列bad_rowsに許可される唯一の値として、マテリアライズドビューに制約を含めました。 は0です。Oracleは、別の値を与えるトランザクションをコミットすることを許可しません。

    したがって、挿入ステートメントの2番目のペアを見ると、誤った行をレシーバーに挿入できたことがわかりますが、コミットしようとするとOracleから制約違反が発生します。




    1. これで、MicrosoftAzureMFAでAccessを使用できるようになりました。

    2. クエリを単一のクエリにマージする方法(またはストアドプロシージャの場合もあります)。

    3. グループ化関数によるJDBC数値タイプの精度の低下を処理する方法

    4. データベースの設計:どちらがより良いアプローチですか?