ORACLE在触发器中以1对多表关系更新记录

马里亚纳

我被困住了,我不知道自己在做什么错,我需要一些帮助!

给定一个映射到一个人的表PERSON

create table person
(
    ID integer,
    registration_number varchar(9),
    primary_number varchar(9),
    women_act varchar(1)
);

给定一个表CONSOLIDATED_NUMBERS该表指定了来自PERSON的多个条目之间的映射:

create table consolidated_numbers
(
    SECONDARY_NUMBER varchar(9),
    person_id integer
);

给定一个表TRANSACTION_HISTORY该表保留了PERSON表中与给定人员相关的所有活动的记录(注意,下面的原因列,上面的有效代码排列)

create table history_transaction
(
    reason varchar(2),
    person_id integer,
    type_id integer,
    action_date date
);
    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 history_transaction (reason,person_id,type_id,action_date) values ('A1', 132, 1420, DATE '2019-01-01');

给定一个表CODE来跟踪有效代码:

    create table code
    (
        valid_code varchar(2)
    );
    insert into code (valid_code) values ('A1');
    insert into code (valid_code) values ('T1');
    insert into code (valid_code) values ('N2');

期望的是,当来自PERSON的personX执行某项操作以使其更新TRANSACTION_HISTORY表时,然后应更新表CONSOLIDATED_NUMBERS中映射的与personX关联的PERSON中的所有人员,以将其women_act列设置为X。

    create or replace TRIGGER trans_hist_trg
        AFTER
    INSERT OR
    UPDATE OF reason
        ON history_transaction
    FOR EACH ROW
    DECLARE
    v_exists   VARCHAR2
    (1);
    v_valid    code.valid_code%TYPE;
    v_person_id     person.id%TYPE;

    BEGIN
        IF(INSERTING) THEN
        v_person_id := :NEW.person_id;
    ELSE
        v_person_id := :OLD.person_id;
    END
    IF;
    BEGIN
        SELECT women_act
        INTO  v_exists
        FROM person
        WHERE id = v_person_id;
        EXCEPTION
        WHEN NO_DATA_FOUND THEN
           v_exists := NULL;
    END;

    SELECT valid_code
    INTO v_valid
    FROM code
    WHERE valid_code = :NEW.reason;

    IF v_exists IS NULL AND :NEW.type_id IN
    (120,140,1420,1440,160,180,150,1520,1540,1560) THEN
    IF :NEW.reason NOT IN
    ('T1','A1') OR
    (:NEW.reason IN
    ('T1','A1') AND :NEW.action_date >= '01-JAN-00') THEN
    BEGIN
        SELECT valid_code
        INTO v_valid
        FROM code
        WHERE valid_code = :NEW.reason;
        EXCEPTION
                WHEN NO_DATA_FOUND THEN
                    v_exists := null;
    END;
    IF v_valid IS NOT NULL THEN
    UPDATE person
                SET women_act = 'X'
                WHERE (id = v_person_id
        OR id IN (SELECT DISTINCT id
        FROM person
        WHERE registration_number IN (SELECT DISTINCT SECONDARY_NUMBER
        FROM consolidated_numbers
        WHERE person_id = v_person_id)));
    END IF;
   END IF;    
  END IF;            
 
END trans_hist_trg;
   ---validate records
    select * from person;
    select * from consolidated_numbers;
    select * from history_transaction;
    select * from code;

    --update reocord to activate trigger 
    update history_transaction
      set reason = 'A1'
      where person_id = 132;

    --should update 2 records (132 and 151 with x. Initially they were null)
    select * from `person`;

我现在的挑战是将横幅设置为所有合并数字。现在,如果我将横幅设置为主要数字,则该横幅将显示在所有辅助数字上;但是,如果我将横幅广告设置在辅助电话号码上,它将不会显示在主电话号码上。

请帮忙!

斯蒂芬

请勿为此使用触发器。您已将大多数条件编码到(触发器的)嵌套IF中,可以通过外键约束和检查约束来完成。另外,您不需要在任何地方存储WOMAN_ACT的“ X”,因为它是“派生值”,即在查询数据时可以获取或生成它。也许以下示例(基于原始表和数据)将帮助您找到解决方案。请阅读代码中的注释。

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

测试数据

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

以下VIEW将从HISTORY_TRANSACTION表中提取person_id,在每个表中添加和“ X”,并从CONSOLIDATED_NUMBERS中提取与这些ID“关联”(或映射到)的所有人员,并添加一个他们的ID为“ X”。(旁注:您的PERSON表似乎包含一个递归关系,因此可以编写一个递归查询。但是,您将需要对CONSOLIDATED_NUMBERS表进行建模,因此我们将在此处使用JOIN。)

视图

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

现在,让我们删除/添加一些数据,并运行一些测试(另请参见: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        |
+---------+---------+

在我们进入更多细节之前的另一项测试:

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

JOIN视图person表

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

对于在HISTORY_TRANSACTION表中没有对应行的PERSON_ID,需要外部联接

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

编辑

如果-如您的注释中所述-您必须在WOMAN_ACT列中存储一个值(尽管它显然是“派生的值”),则可以编写一个包含所有必需DML操作过程的程序包-仍不使用触发器。但是,在不了解全文的情况下,很难决定这是否是最好的方法。以下示例使用一个小型程序包,其中包含用于设置PERSON表的WOMAN_ACT值的过程以及在INSERT / UPDATEs之后触发的触发器(表:HISTORY_TRANSACTIONS)。DBfiddle在这里

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

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

包装体

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

触发

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

测试:请参阅DBfiddle

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

oracle触发器选择更新的行

来自分类Dev

MSSQL触发器-更新INSERT上的新插入的记录

来自分类Dev

在Oracle中创建触发器

来自分类Dev

在触发器中更新表失败

来自分类Dev

更新触发器中插入和删除的记录计数是否总是相等?

来自分类Dev

MySQL触发器,用于更新特定的记录列值

来自分类Dev

创建MySQL触发器以更新另一个表中的多个记录

来自分类Dev

更新触发器如何删除旧记录

来自分类Dev

Oracle触发器不会更新

来自分类Dev

MySQL触发器在更新后删除特定的列记录

来自分类Dev

更新SQL中的触发器

来自分类Dev

Oracle触发器中的RTTI

来自分类Dev

在新插入上更新多表数据的触发器或事务

来自分类Dev

在Oracle中的触发器中,如何从更新中的“ where”中获取信息?

来自分类Dev

多表触发器更新/删除/插入

来自分类Dev

在触发器上更新插入的记录

来自分类Dev

触发器中的SQL ORACLE错误

来自分类Dev

FIM-用于更新Delta表中的记录的SQL触发器

来自分类Dev

数据库多表触发器

来自分类Dev

在MySQL中创建触发器并更新

来自分类Dev

显示使用触发器更新的记录

来自分类Dev

更新触发器中的多行更新

来自分类Dev

Oracle中的PL / SQL触发器

来自分类Dev

Oracle更新触发器问题

来自分类Dev

如何在Oracle中更新触发器

来自分类Dev

想要检查触发器中的约束以在 Oracle 中记录自定义消息

来自分类Dev

涉及多表Oracle、PL/SQL的触发器

来自分类Dev

在oracle中查找表单的触发器

来自分类Dev

Oracle 中的语句级触发器