在插入或更新主 table 后插入另一个 table 的复合触发器

Compound trigger to insert into another table after insert or update into the main table

我正在研究复合触发器,但我很难弄清楚如何让它发挥作用。触发器在 table 上。有一列woman_act。如果插入了一个新行并且该列不为空,那么我们需要将该行插入 v_changes table 或者如果该列是从 null'X' 而不是将该行插入 v_changes table .使用 COMPOUND 触发器是因为我得到 变异 table 并且发生这种情况是因为我从 select.

插入

这是逻辑

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

这是我的触发器。非常感谢任何想法和建议。

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;

这里似乎不需要使用复合触发器,因为不需要查询 person table。只需使用行级触发器并在您的逻辑中引用 :new:old 伪记录

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;

假设您刚刚学习 PL/SQL,创建一些局部变量并在 insert 语句中使用它们可能更容易,即

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;