Oracle
 sql >> Baza danych >  >> RDS >> Oracle

ORACLE aktualizuje rekordy z relacją od 1 do wielu tabel w wyzwalaczu

Nie używaj do tego wyzwalacza. Większość warunków zakodowanych w zagnieżdżonych elementach IF (wyzwalacza) można prawdopodobnie wykonać za pomocą ograniczeń klucza obcego i ograniczeń sprawdzających. Ponadto nie musisz nigdzie przechowywać znaku „X” dla WOMAN_ACT, ponieważ jest to „wartość pochodna”, tj. możesz ją uzyskać lub wygenerować podczas zapytania o swoje dane. Może poniższy przykład (w oparciu o Twoje oryginalne tabele i dane) pomoże Ci znaleźć rozwiązanie. Proszę przeczytać komentarze w kodzie.

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

Dane testowe

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

Poniższy VIEW pobierze person_ids z tabel HISTORY_TRANSACTION, doda i 'X' do każdej z nich, a także pobierze wszystkie osoby, które są "skojarzone" z (lub:zmapowane) z tymi id z CONSOLIDATED_NUMBERS, a także doda „X” do ich identyfikatorów. (Uwaga:wygląda na to, że Twoja tabela PERSON zawiera relację rekurencyjną, więc można by napisać zapytanie rekurencyjne. Jednak będziesz mieć powód do modelowania tabeli CONSOLIDATED_NUMBERS, więc użyjemy tutaj JOIN.)

WIDOK

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

Teraz usuńmy/dodajmy trochę danych i przeprowadźmy kilka testów (patrz też: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        |
+---------+---------+

Kolejny test, zanim przejdziemy do dalszych szczegółów:

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

DOŁĄCZ widok na tabelę osób

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

Połączenie zewnętrzne jest potrzebne w przypadku identyfikatorów PERSON_ID, które nie mają odpowiadających wierszy w tabeli HISTORY_TRANSACTION, np.

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

EDYTUJ

Jeśli - jak stwierdzono w komentarzu - musisz przechowywać wartość w kolumnie WOMAN_ACT (chociaż najwyraźniej jest to "wartość pochodna"), możesz napisać pakiet zawierający procedury dla wszystkich wymaganych operacji DML - nadal bez użycia wyzwalacza. Jednak nie znając całej historii, trudno zdecydować, czy będzie to najlepsza droga naprzód. W poniższym przykładzie zastosowano mały pakiet zawierający procedury ustawiania wartości WOMAN_ACT tabeli PERSON oraz wyzwalacz uruchamiany po wstawieniu/aktualizacji (tabela:HISTORY_TRANSACTIONS). DBfiddle tutaj .

Tabela 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

PAKIET

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

KORPUS PAKIETU

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

WYZWALANIE

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

TESTOWANIE:patrz DBfiddle




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wykonywanie procedury składowanej Oracle w EntityFramework

  2. Wybranie pola Distinct i numeru wiersza tylko w celu wyświetlenia numeru identyfikacyjnego daje zduplikowane dane

  3. Łączenie się z bazą danych Oracle za pomocą Swift po stronie serwera

  4. Jak używać stałej pakietu w instrukcji SQL SELECT?

  5. Funkcja SINH() w Oracle