我正在尝试创建一个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;
/
答案 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语句的条件将找不到任何行。完成!!!