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

トリガー内の1対多のテーブル関係でレコードを更新するORACLE

    これにはトリガーを使用しないでください。 (トリガーの)ネストされたIFにコーディングした条件のほとんどは、外部キー制約とチェック制約を介して実行できる可能性があります。また、WOMAN_ACTの「X」は「派生値」であるため、どこにでも保存する必要はありません。つまり、データをクエリするときに取得または生成できます。次の例(元のテーブルとデータに基づく)は、解決策を見つけるのに役立つかもしれません。コード内のコメントをお読みください。

    DDLコード

    create table person (
      id number primary key
    , registration_number varchar2(9) unique
    , primary_number varchar2(9)
    -- , women_act varchar2(1)   <- not needed!
    ); 
      
    create table consolidated_numbers (
      secondary_number varchar2(9) references person( registration_number )
    , person_id number references person( id )
    ); 
    
    create table code (
      valid_code varchar2(2) primary key
    );
    
    -- CHECK constraint added to allow only certain TYPE_IDs
    create table history_transaction (
      reason varchar2(2) references code( valid_code ) -- valid REASONSs enforced by FK constraint
    , person_id number references person( id )
    , type_id number check (
        type_id in (
          120, 140, 1420, 1440, 160, 180, 150, 1520, 1540, 1560  -- only allow these type_ids
        )
      )
    , action_date date
    );
    

    テストデータ

    -- INSERT your initial test data
    begin
      insert into person (ID,registration_number,primary_number) values(132, '000000001', null);
      insert into person (ID,registration_number,primary_number) values (151, '000000002', '000000001');
      insert into consolidated_numbers (SECONDARY_NUMBER,person_id) values ('000000002', 132);
      insert into code (valid_code) values ('A1');
      insert into code (valid_code) values ('T1');
      insert into code (valid_code) values ('N2');
      insert into history_transaction (reason,person_id,type_id,action_date)
        values ('A1', 132, 1420, DATE '2019-01-01');
      commit ;
    end;
    /
    

    次のビューは、HISTORY_TRANSACTIONテーブルからperson_idsを取得し、それらすべてに「X」を追加します。また、CONSOLIDATED_NUMBERSからこれらのIDに「関連付けられている」(またはマップされている)すべての人を取得し、さらにIDに「X」。 (補足:PERSONテーブルには再帰関係が含まれているため、再帰クエリを記述できます。ただし、CONSOLIDATED_NUMBERSテーブルをモデル化する理由があるため、ここではJOINを使用します。)

    表示

    create or replace view personx
    as
    with PID as (
      select distinct person_id
      from history_transaction
    )
    select person_id, 'X' as woman_act  -- [Q1] all person_ids from history_transaction
    from PID
    union
    select P.id, 'X' as woman_act       -- [Q2] all person_ids associated with ids from Q1
    from person P
      join consolidated_numbers C
        on P.registration_number = C.secondary_number
        and C.person_id in (
          select person_id from PID
        )
    ;
    
    -- with your initial test data, we get:
    select * from personx ;
    +---------+---------+
    |PERSON_ID|WOMAN_ACT|
    +---------+---------+
    |132      |X        |
    |151      |X        |
    +---------+---------+
    

    それでは、いくつかのデータを削除/追加して、いくつかのテストを実行しましょう( DBfiddle > ):

    -- test 1
    delete from history_transaction ;
    select * from personx ;
    -- result: no rows selected -> OK
    
    -- test 2
    insert into history_transaction (reason,person_id,type_id,action_date) 
      values ('A1', 132, 1420, DATE '2019-01-01');
      
    select * from personx ;
    +---------+---------+
    |PERSON_ID|WOMAN_ACT|
    +---------+---------+
    |132      |X        |
    |151      |X        |
    +---------+---------+
    
    -- test 3: add more associations
    begin   
    -- new: person 345 associated with person 132
      insert into person (ID,registration_number,primary_number) values (345, '000000345', '000000001');
      insert into consolidated_numbers (SECONDARY_NUMBER,person_id) values ('000000345', 132);
      commit ;
    end ;
    /
    
    select * from personx ;
    +---------+---------+
    |PERSON_ID|WOMAN_ACT|
    +---------+---------+
    |132      |X        |
    |151      |X        |
    |345      |X        |
    +---------+---------+
    

    詳細に入る前の別のテスト:

    -- test 4
    -- add more associations 
    -- no entry in history_transactions for person(id) 1000        
    begin   
      insert into person (ID,registration_number,primary_number) values(1000, '000000777', null);
      insert into person (ID,registration_number,primary_number) values (2000, '000000778', '000000777');
      insert into consolidated_numbers (SECONDARY_NUMBER,person_id) values ('000000778', 1000);
      commit ;
    end ;
    /   
    
    -- output must be the same as before -> result OK
    select * from personx ;
    +---------+---------+
    |PERSON_ID|WOMAN_ACT|
    +---------+---------+
    |132      |X        |
    |151      |X        |
    |345      |X        |
    +---------+---------+
    

    参加 人物テーブルの表示

    -- test 5
    -- add an entry from person 1000 into the history_transaction table
    insert into history_transaction (reason,person_id,type_id,action_date) 
        values ('N2', 1000, 1420, sysdate);  
    
    select * from personx ;
    +---------+---------+
    |PERSON_ID|WOMAN_ACT|
    +---------+---------+
    |132      |X        |
    |151      |X        |
    |345      |X        |
    |1000     |X        |
    |2000     |X        |
    +---------+---------+
    
    -- test 5: show more details
    select P.id, P.registration_number, P.primary_number, PX.woman_act
    from personx PX right join person P on PX.person_id = P.id ;
    
    +----+-------------------+--------------+---------+
    |ID  |REGISTRATION_NUMBER|PRIMARY_NUMBER|WOMAN_ACT|
    +----+-------------------+--------------+---------+
    |132 |000000001          |NULL          |X        |
    |151 |000000002          |000000001     |X        |
    |345 |000000345          |000000001     |X        |
    |1000|000000777          |NULL          |X        |
    |2000|000000778          |000000777     |X        |
    +----+-------------------+--------------+---------+
    

    外部結合は、HISTORY_TRANSACTIONテーブルに対応する行がないPERSON_IDに必要です(例:

    )。
    -- test 6
    -- add more associations
    -- no entry in history_transactions for person(id) 10000!
    begin
      insert into person (ID,registration_number,primary_number) values(10000, '000007777', null);
      insert into person (ID,registration_number,primary_number) values (20000, '000007778', '000007777');
      insert into consolidated_numbers (SECONDARY_NUMBER,person_id) values ('000007778', 10000);
      commit ;
    end ;
    /
    
    -- after TEST 6 data have been inserted:
    select P.id, P.registration_number, P.primary_number, PX.woman_act
    from personx PX right join person P on PX.person_id = P.id ;
    
    +-----+-------------------+--------------+---------+
    |ID   |REGISTRATION_NUMBER|PRIMARY_NUMBER|WOMAN_ACT|
    +-----+-------------------+--------------+---------+
    |132  |000000001          |NULL          |X        |
    |151  |000000002          |000000001     |X        |
    |345  |000000345          |000000001     |X        |
    |1000 |000000777          |NULL          |X        |
    |2000 |000000778          |000000777     |X        |
    |20000|000007778          |000007777     |NULL     |
    |10000|000007777          |NULL          |NULL     |
    +-----+-------------------+--------------+---------+
    

    編集

    コメントに記載されているように、WOMAN_ACT列に値を格納する必要がある場合(明らかに「派生値」ですが)、トリガーを使用せずに、必要なすべてのDML操作のプロシージャを含むパッケージを作成できます。しかし、完全なストーリーを知らなければ、これが最善の方法であるかどうかを判断するのは困難です。次の例では、PERSONテーブルのWOMAN_ACT値を設定するためのプロシージャと、INSERT / UPDATE(テーブル:HISTORY_TRANSACTIONS)の後に起動するトリガーを含む小さなパッケージを使用しています。 DBfiddle こちら

    PERSONテーブル

    create table person (
      id number primary key
    , registration_number varchar2(9) unique
    , primary_number varchar2(9)
    , woman_act varchar2(1) check ( woman_act in ( null, 'X' ) )
    );
    -- all other tables: same as before
    

    パッケージ

    create or replace package pxpkg
    is
      -- find out whether a certain id (table: PERSON) is a "parent" or a "child"
      function isparent( id_ number ) return boolean ;
      -- set 'X' values: id_ is a "parent"
      procedure setx_parentchildren( id_ number ) ;
      -- set 'X' values: id_ is a "child" 
      procedure setx_childsiblings( id_ number ) ;
    end pxpkg ;
    /
    

    パッケージ本体

    create or replace package body pxpkg
    is
      function isparent( id_ number )
      return boolean
      is
        secondarynumbers pls_integer := 0 ;
      begin
        select count(*) into secondarynumbers
        from consolidated_numbers
        where person_id = id_ ;
        if secondarynumbers = 0 then
          return false ;
        else
          return true ;
        end if ;
      end isparent ;
    --
      procedure setx_parentchildren ( id_ number )
      is
      begin
        update person
        set woman_act = 'X'
        where id in ( 
          select id from person where id = id_ -- parent id
          union
          select id from person 
          where primary_number = ( 
            select registration_number from person where id = id_ -- parent id
          )
        ) ;
      end setx_parentchildren ;
    --
      procedure setx_childsiblings ( id_ number )
      is
      begin
        update person
        set woman_act = 'X'
        where id in ( 
          with PID as (
            select id, primary_number from person
            where id = id_                    -- current id
              and primary_number is not null  -- child ids only
          )
          select id from PID
          union
          select id 
          from person 
          where registration_number in ( select primary_number from PID )
             or primary_number in ( select primary_number from PID )
        ) ;
      end setx_childsiblings ;
    end pxpkg ;
    /
    

    トリガー

    create or replace trigger pxtrigger
    after insert or update on history_transaction
    for each row
    begin
      if pxpkg.isparent( :new.person_id ) then
        pxpkg.setx_parentchildren( :new.person_id )  ;
      else
        pxpkg.setx_childsiblings( :new.person_id )  ;
      end if ;
    end pxtrigger ;
    /
    

    テスト:DBfiddle を参照してください。




    1. ETLプロセスでのPythonとMySQLの使用:PythonとSQLAlchemyの使用

    2. Laravelの大文字と小文字を区別するwhereステートメント

    3. ボタンクリックでMySQLデータベースからHTMLテキストボックスにデータをロードする

    4. OracleQueryの各行に乱数を生成する