2012-06-21 56 views
4

我对触发器相当陌生,所以显然我在某处做错了什么。我正在制作一个报表,它将从原始表中获取数据。为了简单起见,假设有一个表,然后有一个报表。PLSQL触发器更新另一个表中的字段值

原始表(orig_tab)

CREATE TABLE orig_tab (
PK  NUMBER(8)  not null, 
NAME VARCHAR2(20)   , 
); 

INSERT INTO orig_tab (PK, NAME) VALUES (1, 'AAA'); 
INSERT INTO orig_tab (PK, NAME) VALUES (2, 'BBB'); 
INSERT INTO orig_tab (PK, NAME) VALUES (3, 'CCC'); 

;那么,报告表(rep_tab)

CREATE TABLE rep_tab (
PK  NUMBER(8)  not null, 
NAME VARCHAR2(20)   , 
); 
从用户inteface

现在,有人更改记录2的值,显然,这应该如何治疗作为插入(因为此记录不存在)用于报告表。然后在某个时间之后,值被更改,因此它是报告表的更新情况。

问:我该如何制作这种触发器?我认为这是一个合并状态的情况。

这是我做了什么:

create or replace trigger vr_reporting_trigger 
after update on orig_tab 
    for each row 
begin 
    MERGE INTO rep_tab d 
    USING (SELECT pk FROM orig_tab) s 
    ON (d.pk = s.pk) 
    WHEN MATCHED THEN 
    UPDATE SET d.pk = s.pk, 
      d.name = s.name 
    WHEN NOT MATCHED THEN 
    INSERT (d.pk, d.name) VALUES (s.pk, s.name); 
end vr_reporting_trigger; 

的任何意见或建议,可以帮助我的数字出来?谢谢。

+0

好的答案规定,凡发现最大的问题(变异表异常(“每一行”触发不允许从表中选择),可能要AFTER INSERT OR UPDATE触发器,还有一些需要考虑处理的角落案例,比如更新到orig_tab.pk(可能不希望在报表中留下“旧”行);或者如果在插入匹配行时报告表中已存在行到orig_tab。 – spencer7593

回答

3

有一些角落情况在以前的答案中没有处理。

如果匹配的PK已经存在于报表中,当行插入。 (我们通常不会期望发生这种情况,但要考虑如果有人从orig_tab中删除了一行,然后再次插入它,会发生什么情况(这是在生产中会出现的那种问题,而不是测试中的问题,在最不合时宜的时候。现在好了计划吧。)

BEGIN 
    IF inserting THEN 
     -- insure we avoid duplicate key exception with a NOT EXISTS predicate 
     INSERT INTO rep_tab(pk,name) 
     SELECT :new.pk, :new.name FROM DUAL 
     WHERE NOT EXISTS (SELECT 1 FROM rep_tab WHERE pk = :new.pk); 
     -- if row already existed, there's a possibility that name does not match 
     UPDATE rep_tab t SET t.name = :new.name 
     WHERE t.pk = :new.pk; 
     -- could improve efficiency of update by checking if update is actually 
     -- needed using a nullsafe comparison (t.name <=> :new.name); 
    ELSIF updating THEN 
     -- handle updates to pk value (note: the row to be updated may not exist 
     -- so we need to fallthru to the merge) 
     IF :new.pk <> :old.pk THEN 
     UPDATE rep_tab t 
      SET t.pk = :new.pk 
       , t.name = :new.name 
      WHERE t.pk = :old.pk ; 
     END IF; 
     MERGE INTO rep_tab d 
     USING DUAL ON (d.pk = :old.pk) 
     WHEN MATCHED THEN 
     UPDATE SET d.name = :new.name 
     WHEN NOT MATCHED THEN 
     INSERT (d.pk,d.name) VALUES (:new.pk,:new.name); 
    END IF; 
END; 
3

MERGE语句听起来像一个计划,只是因为你提到这是一个AFTER UPDATE触发器,而不是一个AFTER INSERT触发器触发不会当你在做第一次插入点火。

此外,SELECT pk FROM orig_tab将导致Mutating table problem

更好的方式是定义一个AFTER INSERT或UPDATE触发器,与INSERT/UPDATING关键字结合起来,以处理插入/更新&使用:new/:old分别处理新数据&旧数据。

CREATE OR replace TRIGGER vr_reporting_trigger 
    AFTER INSERT OR UPDATE ON orig_tab 
    FOR EACH ROW 
BEGIN 
    IF inserting THEN 
     INSERT INTO rep_tab 
        (pk, 
        name) 
     VALUES  (:NEW.pk, 
        :NEW.name); 
    ELSIF updating THEN 
     UPDATE rep_tab r 
     SET name = :NEW.name 
     WHERE r.pk = :old.pk; 
    END IF; 
END vr_reporting_trigger; 
+0

感谢Sathya的回应。我可以在更新中看到一些小问题:如果记录在orig_tab中更新并且在rep_tab中没有对应的记录,则此逻辑可能不起作用 – Jaanna

+0

@Jaanna如果记录不存在,您可以检查记录的存在并插入记录 – Sathya

+0

elsif如果rep_tab.pk <>:old.pk,则更新 然后 INSERT INTO rep_tab(pk,name)VALUES(:NEW.pk,:NEW.name); else UPDATE rep_tab r SET name =:NEW.name WHERE r.pk =:old.pk; endif; 不起作用 – Jaanna

1

这是Sathya AnswerJaanna被问及如果记录在orrig_tab更新的延伸,在rep_tab没有相应的记录,则下面的逻辑将满足下面,请您及时请求不同意这个答案评判我此解决方案属于Sathya

CREATE OR replace TRIGGER vr_reporting_trigger 
    AFTER INSERT OR UPDATE ON orig_tab 
    FOR EACH ROW 
BEGIN 
    IF inserting THEN 
     INSERT INTO rep_tab 
        (pk, 
        name) 
     VALUES  (:NEW.pk, 
        :NEW.name); 
    ELSIF updating THEN 
     MERGE INTO rep_tab d 
      USING DUAL 
     ON (d.pk =:OLD.pk) 
     WHEN MATCHED THEN 
     UPDATE SET d.name = :OLD.name    
     WHEN NOT MATCHED THEN 
     INSERT (d.pk,d.name) VALUES (:OLD.PK,:NEW.PK); 
    END IF; 
END vr_reporting_trigger; 
+0

@Sathya:请验证我的除了你的解决方案,谢谢 –

+0

@Guarav:在INSERT(当不匹配),不应该是'VALUES(:new.PK,:new.name)'?而在更新(匹配时)应该不是'd.name =:new.name'?这是否处理pk列的值更新时的情况? – spencer7593

+0

@GauravSoni您的评论应该在我的回答中,我没有收到通知。另外,不要将分号添加到名称中。话虽如此,这似乎很好。 – Sathya

相关问题