0

我已经为表格库存创建了一个触发器

该表的架构如下:

create table stock(item_code varchar2(2) primary key, p_qty number(2),s_qty number(2));

触发器如下:

CREATE OR REPLACE TRIGGER TR_STOCK BEFORE UPDATE OF S_QTY ON STOCK FOR EACH ROW
DECLARE
    V_P STOCK.P_QTY%TYPE;
    V_S STOCK.S_QTY%TYPE;
    V_I VARCHAR2(2);
BEGIN
    V_S:=:NEW.S_QTY;
    V_I:=:NEW.ITEM_CODE;
    SELECT P_QTY INTO V_P FROM STOCK WHERE ITEM_CODE=V_I;
    IF V_S>V_P THEN
        RAISE_APPLICATION_ERROR(-20400,'SOLD QTY CANNOT EXCEED PURCHASED QTY...');
    END IF;
END;
/

现在每次我执行更新查询时,它都会说表正在变异并标记以下错误:

update stock set s_qty=2 where item_code='i4'
       *
ERROR at line 1:
ORA-04091: table HR.STOCK is mutating, trigger/function may not see it
ORA-06512: at "HR.TR_STOCK", line 8
ORA-04088: error during execution of trigger 'HR.TR_STOCK'

对这个特定问题有任何帮助吗?

4

2 回答 2

2

无需查询STOCK表。直接比较:NEW.P_QTY:NEW.S_QTY字段

CREATE OR REPLACE TRIGGER TR_STOCK BEFORE UPDATE OF S_QTY ON STOCK FOR EACH ROW
DECLARE
BEGIN
    IF :new.s_qty > :new.p_qty THEN
        RAISE_APPLICATION_ERROR(-20400,'SOLD QTY CANNOT EXCEED PURCHASED QTY...');
    END IF;
END;
/
于 2012-06-25T15:47:50.173 回答
2

您确实应该考虑使用数据库约束来实现此逻辑,在这种情况下您根本不需要触发器。

ALTER TABLE hr.stock 
ADD CONSTRAINT stock_ck1
CHECK (
  s_qty <= p_qty
)

与约束相比,触发器有很多缺点:

  • 触发器不考虑现有数据行,如果您愿意,约束可以这样做。
  • 触发器必须FOR EACH ROW每一行在SQL 引擎和 PL/SQL 引擎之间进行上下文切换,这增加了INSERTorUPDATE语句运行的开销。随着行数的增加,这会增加。
  • Oracle 在优化 SQL 语句时可以使用约束(它知道WHERE违反CHECK约束的子句将永远不会返回任何行而不需要检查行)。

如果您使用触发器来提供错误消息,您应该真正考虑将其移动到您的应用程序逻辑中,并使用约束作为保障。

于 2012-06-27T23:16:04.583 回答