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