考虑以下Oracle触发器,该触发器不起作用,因为每个if语句中都有一个子句
CREATE OR REPLACE TRIGGER track_rm_area_t
BEFORE UPDATE OR INSERT ON RM
FOR EACH ROW
BEGIN
IF(:NEW.area IS NOT NULL) THEN
INSERT INTO rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area, date_effective, usable_flag)
VALUES(:NEW.bl_id, :NEW.fl_id, :NEW.rm_id, :NEW.rm_cat, :NEW.rm_type, :NEW.area, SYSDATE,
CASE WHEN :NEW.rm_cat IN (SELECT rm_cat FROM rmcat WHERE supercat = 'USBL') THEN 1 ELSE 0 END);
ELSIF(:NEW.rm_cat IS NOT NULL AND :OLD.rm_cat IS NOT NULL AND (:NEW.rm_cat <> :OLD.rm_cat)) THEN
IF(
:NEW.rm_cat IN (SELECT rm_cat FROM rmcat WHERE supercat = 'USBL')
AND :OLD.rm_cat NOT IN (SELECT rm_cat FROM rmcat WHERE supercat = 'USBL')
) THEN
INSERT INTO rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area, date_effective, usable_flag)
VALUES(:NEW.bl_id, :NEW.fl_id, :NEW.rm_id, :NEW.rm_cat, :NEW.rm_type, :NEW.area, SYSDATE, 1);
ELSIF
(
:NEW.rm_cat NOT IN (SELECT rm_cat FROM rmcat WHERE supercat = 'USBL')
AND :OLD.rm_cat IN (SELECT rm_cat FROM rmcat WHERE supercat = 'USBL')
) THEN
INSERT INTO rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area, date_effective, usable_flag)
VALUES(:NEW.bl_id, :NEW.fl_id, :NEW.rm_id, :NEW.rm_cat, :NEW.rm_type, :NEW.area, SYSDATE, 0);
END IF;
END IF;
END;
/
COMMIT;
总体而言,我要完成的工作是:
rm_area.usable_flag
应该为1,否则为0。如果rm.rm_cat IN (SELECT rm_cat FROM rmcat WHERE rmcat.supercat = 'USBL')
我知道我需要一个变量和循环来遍历子查询中的所有值,但是不确定如何最好地考虑这一点。当我尝试以下操作时:
CREATE OR REPLACE TRIGGER track_rm_area_t
BEFORE UPDATE OR INSERT ON RM
FOR EACH ROW
DECLARE
usable_rm_cat VARCHAR(12 BYTE);
BEGIN
FOR r IN (SELECT rm_cat INTO usable_rm_cat FROM rmcat WHERE supercat = 'USBL')
LOOP
usable_rm_cat := r.rm_cat;
IF
(
:NEW.area IS NOT NULL OR
(
:NEW.rm_cat IS NOT NULL AND :OLD.rm_cat IS NOT NULL AND (:NEW.rm_cat <> :OLD.rm_cat) AND
(
(:OLD.rm_cat IN (usable_rm_cat)
AND :NEW.rm_cat NOT IN (usable_rm_cat))
OR (:OLD.rm_cat NOT IN (usable_rm_cat)
AND :NEW.rm_cat IN (usable_rm_cat))
)
)
) THEN
INSERT INTO rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area, date_effective, usable_flag)
VALUES(:NEW.bl_id, :NEW.fl_id, :NEW.rm_id, :NEW.rm_cat, :NEW.rm_type, :NEW.area, SYSDATE,
CASE WHEN :NEW.rm_cat IN (usable_rm_cat) THEN 1 ELSE 0 END);
EXIT;
END IF;
END LOOP;
END;
/
COMMIT;
insert语句中的CASE
总是产生0
。
要解决此问题,我考虑过从循环开始,然后检查是否为:NEW.rm_cat = r.rm_cat
,但这使我无法确定如何最好地检查:OLD.rm_cat
的值并处理所有更新的情况到rm.area区域需要进行跟踪(这要优先于rm_cat的任何值)。
如何创建触发器,以便跟踪rm.area的所有值并将其插入此新表中,以及rm.rm_cat的特定值?
答案 0 :(得分:1)
我认为您使事情复杂化了,尤其是在这里不需要任何循环。首先在变量中选择值,然后在插入时使用它们:
create or replace trigger track_rm_area_t
before update or insert on rm for each row
v_old_usable int;
v_new_usable int;
begin
select nvl(max(case rm_cat when :old.rm_cat then 1 end), 0),
nvl(max(case rm_cat when :new.rm_cat then 1 end), 0)
into v_old_usable, v_new_usable
from rmcat
where rm_cat in (:old.rm_cat, :new.rm_cat) and supercat = 'USBL';
if :new.area is not null then
insert into rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area,
date_effective, usable_flag)
values(:new.bl_id, :new.fl_id, :new.rm_id, :new.rm_cat, :new.rm_type, :new.area,
sysdate, v_new_usable);
elsif :new.rm_cat is not null and :old.rm_cat is not null and :new.rm_cat <> :old.rm_cat
and v_old_usable <> v_new_usable then
insert into rm_area(bl_id, fl_id, rm_id, rm_cat, rm_type, area,
date_effective, usable_flag)
values(:new.bl_id, :new.fl_id, :new.rm_id, :new.rm_cat, :new.rm_type, :new.area,
sysdate, v_new_usable);
end if;
end;
我没有您的桌子,所以没有经过测试。希望对您有所帮助:)
答案 1 :(得分:0)
触发器应始终非常轻巧。尽管一直在执行此操作,但许多人认为用触发器维护辅助表是一种不好的形式。我已经做到了,对此感到遗憾。我希望您永远不必使用这样的触发器进行批量加载。也就是说,请在插入内容之外进行计数。这是您的SQL的第一部分:
CREATE OR REPLACE TRIGGER track_rm_area_t
BEFORE UPDATE OR INSERT
ON rm
FOR EACH ROW
DECLARE
l_cnt INTEGER;
BEGIN
IF (:new.area IS NOT NULL)
THEN
SELECT COUNT( * ) c
INTO l_cnt
FROM rmcat
WHERE supercat = 'USBL' AND rm_cat = :new.rm_cat AND ROWNUM = 1;
INSERT INTO rm_area( bl_id
, fl_id
, rm_id
, rm_cat
, rm_type
, area
, date_effective
, usable_flag )
VALUES ( :new.bl_id
, :new.fl_id
, :new.rm_id
, :new.rm_cat
, :new.rm_type
, :new.area
, SYSDATE
, l_cnt );
. . .