I’m working on a compound trigger and I’m having difficulties figuring out how to make it work. The trigger is on the person table. There is a column woman_act. If a new row is inserted and that column is not null than we need to insert that row into the v_changes table or if that column is updated from null to ‘X’ than insert that row into v_changes table. Going with COMPOUND trigger becuase I was getting mutating table and that was happening becuase I’m inserting from select.
Here is the logic
--Insert with person.woman_act == ‘ ’ do nothing
--Insert with person.woman_act == ‘X’ insert with is_vawa = 1/true
--Update with person.woman_act changed from ‘ ‘ to ‘X’ insert with is_woman_act = 1/true
create table person (
id number primary key,
reg_number varchar2(9),
last_name charchar2(255),
first_name charchar2(255),
dob date,
birth_c_id number(38,0),
cit_country_id number(38,0),
poe_id number(38,0),
woman_act varchar2(1) check (woman_act in (null, 'X'))
);
create table v_changes (
id number primary key,
person_id number not null,
reg_number varchar2(9),
last_name charchar2(255),
first_name charchar2(255),
dob date,
b_country varchar2(255),
cit_country varchar2(255),
poe varchar2(30),
is_woman_act number(1,0)
);
create table country_code (
id number primary key,
valid_code varchar2(255)
);
create table loc_code (
id number primary key,
valid_code varchar2(255)
);
Here is my trigger. Any ideas and suggestions much appreciated.
CREATE OR REPLACE TRIGGER v_changes_trg
FOR INSERT OR UPDATE OF woman_act ON person
COMPOUND TRIGGER
TYPE t_vawa_type IS TABLE OF person.woman_act%TYPE;
t_vawa t_vawa_type := t_vawa_type();
TYPE t_v_id IS TABLE OF person.id%TYPE;
v_ids t_v_id :=t_v_id();
BEFORE STATEMENT IS
t_vawas := t_vawa_type();
v_ids :=t_v_id();
END BEFORE STATEMENT;
BEFORE EACH ROW IS
t_vawa_id person.id%ROWTYPE;
BEGIN
IF INSERTING AND :NEW.woman_act IS NOT NULL THEN
v_id.extend;
v_ids(v_ids.last) := :NEW.v_ids;
END IF;
IF UPDATING AND (:NEW.woman_act IS NOT NULL AND :OLD.woman_act IS NULL) OR (:OLD.woman_act <> :NEW.woman_act) THEN
v_id.extend;
v_ids(v_ids.last) := :OLD.v_ids;
END IF;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN 1..v_ids.LAST LOOP
INSERT INTO v_changes(
id,
person_id,
reg_number,
last_name,
first_name,
dob,
b_country,
cit_country,
poe,
is_woman_act
)
SELECT
v_changes_seq.nextval,
p.id, --personId
p.reg_number,
p.last_name,
p.first_name,
p.dob,
cc1.valid_code,
cc2.valid_code,
poe.valid_code,
(case woman_act when 'X' then 1 else 0 end)
FROM person p
LEFT JOIN country_code cc1 ON p.birth_c_id = cc1.id
LEFT JOIN country_code cc2 ON p.cit_country_id = cc2.id
LEFT JOIN loc_code poe ON p.poe_id = poe.id
END LOOP;
END AFTER STATEMENT;
END vawa_changes_trg;
Advertisement
Answer
There doesn’t appear to be a need to use a compound trigger here because there is no need to query the person
table. Just use a row-level trigger and reference the :new
and :old
pseudorecords in your logic
create or replace trigger trg_biur_person
before insert or update on person
for each row
begin
IF :new.woman_act = 'X'
THEN
INSERT INTO v_changes(
id,
person_id,
reg_number,
last_name,
first_name,
dob,
b_country,
cit_country,
poe,
is_woman_act
)
SELECT
v_changes_seq.nextval,
:new.id, --personId
:new.reg_number,
:new.last_name,
:new.first_name,
:new.dob,
(select cc1.valid_code
from country_code cc1
where cc1.id = :new.birth_c_id),
(select cc2.valid_code
from country_code cc2
where cc2.id = :new.cit_country_id),
(select poe.valid_code
from loc_code poe
where poe.poe_id = :new.birth_c_id),
(case :new.woman_act when 'X' then 1 else 0 end)
from dual;
end if;
end;
Assuming you’re just learning PL/SQL, it may be easier to create some local variables and use those in your insert
statement, i.e.
create or replace trigger trg_biur_person
before insert or update on person
for each row
declare
l_b_country v_changes.b_country%type;
begin
begin
select cc1.valid_code
into l_b_country
from country_code cc1
where cc1.id = :new.birth_c_id;
exception
-- The fact that you're trying to do a `left join` makes me believe
-- that you want to allow someone to insert a row with a `birth_c_id`
-- that doesn't exist in the `country_code` table. That doesn't make
-- sense to me but that's what I'm going with. If that isn't a valid
-- use case, you can omit the exception handler
when no_data_found
then
l_b_country := null;
end;
insert into v_changes
values( , l_b_country, );
end;