sql >> Database teknologi >  >> RDS >> Oracle

ORACLE opdaterer poster med 1 til mange tabelrelationer i en trigger

Brug ikke en trigger til dette. De fleste af de betingelser, som du har kodet ind i de indlejrede IF'er (af din trigger), kan sandsynligvis udføres via begrænsninger for fremmednøgle og kontrolbegrænsninger. Du behøver heller ikke gemme 'X'et for WOMAN_ACT nogen steder, da det er en "afledt værdi", dvs. du kan få eller generere det, når du forespørger på dine data. Måske vil følgende eksempel (baseret på dine originale tabeller og data) hjælpe dig med at finde en løsning. Læs venligst kommentarerne i koden.

DDL-kode

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

Testdata

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

Følgende VIEW vil hente person_id'er fra HISTORY_TRANSACTION-tabellerne, tilføje og 'X' til hver enkelt af dem, og også samle alle personer, der er "associeret" med (eller:kortlagt til) disse id'er fra CONSOLIDATED_NUMBERS, og tilføjer også en 'X' til deres id'er. (Sidebemærkning:det ser ud til, at din PERSON-tabel indeholder et rekursivt forhold, så man kunne skrive en rekursiv forespørgsel. Du vil dog have en grund til at modellere CONSOLIDATED_NUMBERS-tabellen, så vi vil bruge en JOIN her.)

SE

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

Lad os nu fjerne/tilføje nogle data og køre et par tests (se også:> ):

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

Endnu en test, før vi går ind i flere detaljer:

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

DELTAG udsigten til personbordet

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

Den ydre joinforbindelse er nødvendig for PERSON_ID'er, der ikke har nogen tilsvarende rækker i tabellen HISTORY_TRANSACTION, f.eks.

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

REDIGER

Hvis du - som angivet i din kommentar - skal gemme en værdi i WOMAN_ACT-kolonnen (selvom det tilsyneladende er en "afledt værdi"), kan du skrive en pakke, der indeholder procedurer for alle nødvendige DML-operationer - stadig uden at bruge en trigger. Men uden at kende hele historien er det svært at afgøre, om dette ville være den bedste vej frem. Følgende eksempel bruger en lille pakke, der indeholder procedurer til indstilling af WOMAN_ACT-værdier i PERSON-tabellen og en trigger, der udløses efter INSERTs/UPDATEs (tabel:HISTORY_TRANSACTIONS). DBfiddle her .

PERSON-tabel

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
 

PAKKE

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

PAKKEBOD

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

TRIGGER

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:se DBfiddle




  1. Hvordan man betinget håndterer division med nul med MySQL

  2. ASP.NET/Identity Error:Enhedstypen ApplicationUser er ikke en del af modellen for den aktuelle kontekst

  3. Oracle Apex:Opret en statuslinje, når du venter på resultat

  4. Hvordan sletter man fra flere tabeller i MySQL?