PL / SQL触发器递归错误

时间:2015-11-06 14:56:20

标签: oracle plsql

我正在尝试创建一个PL / SQL语句级触发器,它将在插入或更新语句之后执行。触发器的作用是对于数量(p_qoh)为50或更高的产品,其产品折扣将加倍。除产品不能超过50%的折扣。我的触发器成功符合,但是当我尝试更新产品表时,我得到“达到的最大递归SQL级别数”。任何帮助都非常适合。

CREATE OR REPLACE TRIGGER TRG_AlterDiscount
AFTER INSERT OR UPDATE OF p_qoh, p_discount ON product
DECLARE
  v_p_code      product.p_code%type;
  v_p_discount  product.p_discount%type;
  v_p_qoh       product.p_qoh%type;
CURSOR v_cursor IS SELECT p_discount, p_qoh, p_code FROM product;
BEGIN
  OPEN v_cursor;
LOOP
  FETCH v_cursor INTO v_p_discount, v_p_qoh, v_p_code;
  EXIT WHEN v_cursor%NOTFOUND;
  IF v_p_qoh > 50 AND v_p_discount <= .25 THEN
    UPDATE product SET p_discount = v_p_discount *2 WHERE v_p_code = p_code;
  ELSIF v_p_qoh > 50 AND v_p_discount > .26 THEN
    UPDATE product SET p_discount = .50 WHERE v_p_code = p_code;
  ELSIF v_p_qoh > 50 AND v_p_discount = 0 THEN
    UPDATE product SET p_discount = .05 WHERE v_p_code = p_code;
  ELSE
    NULL;
END IF;
END LOOP;
END;
/

1 个答案:

答案 0 :(得分:1)

您只需要更新其更新或插入的记录的值。

你可以使用FOR EACH ROW Trigger和Pseudorecord。 See here

CREATE OR REPLACE TRIGGER TRG_AlterDiscount
BEFORE INSERT OR UPDATE OF p_qoh, p_discount ON product
FOR EACH ROW
BEGIN
  IF :NEW.p_qoh > 50 AND :NEW.p_discount <= .25 THEN
    :NEW.p_discount := :NEW.p_discount *2;
  ELSIF :NEW.p_qoh > 50 AND :NEW.p_discount > .26 THEN
    :NEW.p_discount := .50;
  END IF; 
END;
/

编辑:

对于像这样的函数,行级别触发器优于语句级别触发器,因为您必须考虑2个问题。

首先,递归错误。更新触发触发的同一个表(以及更新触发器的列)时发生错误。触发器会一次又一次地发射。

实施例。你更新了(p_qoh = 100,p_discount = 0)然后触发了。

有条件,触发器更新(p_discount = .5),然后再次触发。

使用条件,触发器更新(p_discount = .1)然后再次触发触发器。

使用条件,触发器更新(p_discount = .2)然后再次触发触发器。

使用条件,触发器更新(p_discount = .4)然后再次触发触发器。

使用条件,触发器更新(p_discount = .5)然后再次触发触发器。

使用条件,触发器再次更新(p_discount = .5)然后再次触发触发。 ...无限!!!

为避免这种情况,您可以在p_discount = .5

时为停止触发添加更多条件,如下所示
ELSIF v_p_qoh > 50 AND v_p_discount = .5 THEN
    NULL;
ESLE ...

其次,你会得到错误的数据,如前面的例子。你只需要p_discount = .05,但你得到了p_discount = .5

为了避免这种情况,您需要一些控制数据,在更新数据时将其更新为1以使触发器知道哪条记录已更新。触发更新数据时将其更新为0。使用此触发器只会触发一次。

CREATE OR REPLACE TRIGGER TRG_AlterDiscount
AFTER INSERT OR UPDATE OF p_qoh, p_discount ON product
DECLARE
  v_p_code      product.p_code%type;
  v_p_discount  product.p_discount%type;
  v_p_qoh       product.p_qoh%type;
CURSOR v_cursor IS SELECT p_discount, p_qoh, p_code FROM product WHEN p_ctrl =1;
BEGIN
  OPEN v_cursor;
LOOP
  FETCH v_cursor INTO v_p_discount, v_p_qoh, v_p_code;
  EXIT WHEN v_cursor%NOTFOUND;
  IF v_p_qoh > 50 AND v_p_discount <= .25 THEN
    UPDATE product 
        SET p_discount = v_p_discount *2, 
        SET p_ctrl = 0 
    WHERE v_p_code = p_code;
  ELSIF v_p_qoh > 50 AND v_p_discount > .26 THEN
    UPDATE product 
        SET p_discount = .50, 
        SET p_ctrl = 0 
    WHERE v_p_code = p_code;
  ELSIF v_p_qoh > 50 AND v_p_discount = 0 THEN
    UPDATE product 
        SET p_discount = .05,
        SET p_ctrl = 0  
    WHERE v_p_code = p_code;
  ELSE
    UPDATE product 
        SET p_ctrl = 0  
    WHERE v_p_code = p_code;
END IF;
END LOOP;
END;

实施例。你更新了(p_qoh = 100,p_discount = 0,p_ctrl = 1)然后触发了。

使用条件,触发器更新(p_discount = .05,p_ctrl = 0)然后触发器触发。

使用select语句的条件将找不到任何行。完成!!!