[英]Before UPDATE Trigger PL/SQL
我有下表:
对战-名字是PK
姓名 | B_date |
---|---|
战斗1 | 1989 年 1 月 1 日 |
战斗2 | 1996 年 8 月 23 日 |
后果 - (Ship, Battle) 是 UK,Battle 是 FK to Battles
船 | 战斗 | 结果 |
---|---|---|
船X | 战斗1 | 安然无恙 |
船X | 战斗2 | 安然无恙 |
如果该船参加了在当前战斗之后发生的战斗,我必须创建一个触发器来停止将结果列更新为“已摧毁”。 例如,我不应该能够将表 Consequences 中行 (ShipX, Battle1) 中的结果更新为“destroyed”,因为 ShipX 还参与了 Battle1 之后发生的 Battle2。
为了检查 ShipX 是否参加了当前战斗之后发生的其他战斗,我创建了以下 function:
CREATE OR REPLACE FUNCTION check_date_func (p_ship IN VARCHAR, p_battle IN VARCHAR) RETURN BOOLEAN IS
CURSOR battles_curs IS
SELECT c.ship, b.name, b.b_date FROM battles b JOIN consequences c ON (b.name = c.battle);
TYPE t_battles IS TABLE OF battles_curs%ROWTYPE INDEX BY BINARY_INTEGER;
battles_tab t_battles;
v_index BINARY_INTEGER := 0;
v_date DATE;
v_flag BOOLEAN;
BEGIN
SELECT b_date INTO v_date FROM battles b JOIN consequences c ON (b.name = c.battle) WHERE battle = p_battle AND ship = p_ship;
FOR record IN battles_curs LOOP
v_index := v_index + 1;
batalii_tab(v_index).ship := record.ship;
batalii_tab(v_index).name := record.name;
batalii_tab(v_index).b_date := record.b_date;
END LOOP;
FOR i IN battles_tab.FIRST..battles_tab.LAST LOOP
IF battles_tab(i).ship = p_ship AND battles_tab(i).name = p_battle AND battles_tab(i).b_date > v_date THEN
v_flag := TRUE;
RETURN v_flag;
ELSE
v_flag := FALSE;
RETURN v_flag;
END IF;
END LOOP;
END check_date_func;
function 运行没有错误。 之后,我创建了触发器,我将其称为 function。我创建了一个复合触发器,以避免发生变异表错误。
CREATE OR REPLACE TRIGGER update_result_trigg
FOR UPDATE OF result ON consequences COMPOUND TRIGGER
TYPE t_consequences IS TABLE OF consequences%ROWTYPE INDEX BY BINARY_INTEGER;
consequences_tab t_consequences;
v_index BINARY_INTEGER := 0;
AFTER EACH ROW IS
BEGIN
v_index := v_index + 1;
consecinte_tab(v_index).ship := :NEW.ship;
consecinte_tab(v_index).battle := :NEW.battle;
consecinte_tab(v_index).result := :NEW.result;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN consequences_tab.First..consequences_tab.LAST LOOP
IF check_date_func(:OLD.ship, :OLD.battle) = FALSE AND :NEW.result = 'destroyed' THEN
UPDATE consequences
SET result= :OLD.result
WHERE :OLD.ship= :NEW.ship AND :OLD.battle = :NEW.battle;
RAISE_APPLICATION_ERROR(-20500, 'Nu poti actualiza!');
END IF;
END LOOP;
END AFTER STATEMENT;
END;
唯一的问题是我不能在 AFTER STATEMENT 中使用:OLD 和:NEW。 我怎样才能解决这个问题?
您可以使用:
CREATE OR REPLACE TRIGGER update_result_trigg
FOR UPDATE OF result ON consequences
COMPOUND TRIGGER
TYPE t_consequences IS TABLE OF consequences%ROWTYPE;
v_cons t_consequences := t_consequences();
AFTER EACH ROW IS
BEGIN
IF :NEW.result = 'destroyed' THEN
v_cons.EXTEND;
v_cons(v_cons.COUNT).ship := :NEW.ship;
v_cons(v_cons.COUNT).battle := :NEW.battle;
v_cons(v_cons.COUNT).result := :NEW.result;
END IF;
END AFTER EACH ROW;
AFTER STATEMENT IS
v_rn PLS_INTEGER;
BEGIN
FOR i IN 1 .. v_cons.COUNT LOOP
SELECT rn
INTO v_rn
FROM (
SELECT c.battle,
ROW_NUMBER() OVER (ORDER BY b.b_date DESC) AS rn
FROM consequences c
INNER JOIN battles b
ON (c.battle = b.name)
WHERE c.ship = v_cons(i).ship
) c
WHERE battle = v_cons(i).battle;
IF v_rn > 1 THEN
RAISE_APPLICATION_ERROR(-20500, 'Nu poti actualiza!');
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
如果你尝试:
UPDATE consequences
SET result = 'destroyed'
WHERE ship = 'ShipX'
AND battle = 'Battle1';
那么output就是:
ORA-20500: Nu poti actualiza: ORA-06512. at "FIDDLE_XOXAMEWVYHYVRZLDYCFN,UPDATE_RESULT_TRIGG": line 30 ORA-04088. error during execution of trigger 'FIDDLE_XOXAMEWVYHYVRZLDYCFN.UPDATE_RESULT_TRIGG'
并且因为引发了异常,所以事务被回滚(您不需要手动尝试重置值)。
但是如果你使用:
UPDATE consequences
SET result = 'destroyed'
WHERE ship = 'ShipX'
AND battle = 'Battle2';
然后更新该行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.