繁体   English   中英

UPDATE 触发 PL/SQL 之前

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM