我对触发器很陌生,所以显然我在某处做错了。我正在处理一个报告表,它将从原始表中获取数据。为简单起见,假设有一个表,然后有一个报告表。
原始表格(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) ,
);
现在,从用户界面,有人更改记录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 :(得分:3)
合并语句听起来像一个计划,除了你在第一次插入时触发器不会触发,因为你提到它是一个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;
答案 1 :(得分: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;
答案 2 :(得分:1)
这是Sathya Answer
Jaanna
的扩展,因为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;
询问记录是否在orrig_tab中更新而在rep_tab中没有相应的记录,然后下面的逻辑将满足下面的请求。请不要评判我这个解决方案属于Sathya
{{1}}