Oracle
 sql >> Base de données >  >> RDS >> Oracle

ORACLE mettant à jour les enregistrements avec une relation de table 1 à plusieurs dans un déclencheur

N'utilisez pas de déclencheur pour cela. La plupart des conditions que vous avez codées dans les IF imbriqués (de votre déclencheur) peuvent probablement être effectuées via des contraintes de clé étrangère et des contraintes de vérification. De plus, vous n'avez pas besoin de stocker le 'X' pour WOMAN_ACT nulle part, car il s'agit d'une "valeur dérivée", c'est-à-dire que vous pouvez l'obtenir ou la générer lors de l'interrogation de vos données. Peut-être que l'exemple suivant (basé sur vos tables et données d'origine) vous aidera à trouver une solution. Veuillez lire les commentaires dans le code.

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

Données de test

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

La VUE suivante récupèrera les person_ids des tables HISTORY_TRANSACTION, ajoutera un "X" à chacune d'entre elles, et récupèrera également toutes les personnes qui sont "associées" à (ou :mappées à) ces identifiants à partir de CONSOLIDATED_NUMBERS, et ajoutera également un 'X' à leurs identifiants. (Remarque :il semble que votre table PERSON contient une relation récursive, donc on pourrait écrire une requête récursive. Cependant, vous aurez une raison de modéliser la table CONSOLIDATED_NUMBERS, nous allons donc utiliser un JOIN ici.)

AFFICHER

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        |
+---------+---------+

Maintenant, supprimons/ajoutons des données et exécutons quelques tests (voir aussi :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        |
+---------+---------+

Un autre test avant d'entrer dans plus de détails :

-- 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        |
+---------+---------+

JOIGNEZ-VOUS la vue de la table des personnes

-- 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        |
+----+-------------------+--------------+---------+

La jointure externe est nécessaire pour les PERSON_ID qui n'ont pas de lignes correspondantes dans la table HISTORY_TRANSACTION, par exemple

-- 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     |
+-----+-------------------+--------------+---------+

MODIFIER

Si - comme indiqué dans votre commentaire - vous devez stocker une valeur dans la colonne WOMAN_ACT (bien qu'il s'agisse apparemment d'une "valeur dérivée"), vous pouvez écrire un package contenant des procédures pour toutes les opérations DML requises - toujours sans utiliser de déclencheur. Cependant, sans connaître toute l'histoire, il est difficile de décider si ce serait la meilleure voie à suivre. L'exemple suivant utilise un petit package contenant des procédures pour définir les valeurs WOMAN_ACT de la table PERSON et un déclencheur qui se déclenche après les INSERT/UPDATE (table :HISTORY_TRANSACTIONS). DBfiddle ici .

tableau 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

FORFAIT

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

CORPS DE L'EMBALLAGE

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

DÉCLENCHEUR

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

TEST :voir DBfiddle