0

我正在开发一个简单的触发器,在添加新发票行时更新产品的现有数量。我的工作正常;但我开始认为,在实际应用中,在允许更新之前验证 QOH 是否足够是谨慎的做法。我确定我可以为此编写一个单独的触发器,但我想看看是否可以在触发器中为条件语句连接两个表。

这是据我所知;在那里的任何地方添加一个 SELECT 语句会导致所有的地狱都崩溃,所以我有点难过如何在调用条件之前声明 PRODUCT.P_QOH。

CREATE OR REPLACE TRIGGER trg_prod_QOH_on_line_add
    BEFORE INSERT ON LINE
    FOR EACH ROW
    BEGIN
        IF :NEW.LINE_UNITS > PRODUCT.P_QOH THEN
            RAISE_APPLICATION_ERROR(-20202, 'Insufficient quantity on hand');
        ELSE
            UPDATE PRODUCT
                SET P_QOH = P+QOH - :NEW.LINE_UNITS;
                WHERE PRODUC.P_CODE = :NEW.P_CODE;
        END IF;
    END;
/

这对我来说不是什么大问题,因为我说过可能有不同的方法;我刚开始学习这些东西,想看看有什么可能。谢谢你的帮助。

4

1 回答 1

3

你进入了危险的领域,试图通过触发器来执行这样的规则。您要求的解决方案是:

create or replace trigger trg_prod_qoh_on_line_add
    before insert on line
    for each row
    declare
        v_qoh product.p_qoh%type;
    begin
        select p_qoh
        into   v_qoh
        from   product
        where  product.p_code = :new.p_code;

        if :new.line_units > v_qoh then
            raise_application_error(-20202, 'Insufficient quantity on hand');
        else
            update product
                set p_qoh = p_qoh - :new.line_units
                where product.p_code = :new.p_code;
        end if;
    end;

但是,在具有多个并发用户的系统中,这不是一个安全的解决方案。假设产品“X”的 p_qoh=10,然后有 2 个用户这样做:

user1> insert into line (p_code, line_units) values ('X', 7);

user2> insert into line (p_code, line_units) values ('X', 8);

user1> commit;

user2> commit;

两个会话都会看到 'X' 的 p_qoh = 10,因此两者都会成功,product.p_qoh 最终会变为 -5。一切都是腐败的!

安全的解决方案是对产品创建一个检查约束:

alter table product add constraint prod_qoh_chk check (p_qoh >= 0);

现在您的触发器可以很简单:

create or replace trigger trg_prod_qoh_on_line_add
    before insert on line
    for each row
    begin
        update product
        set p_qoh = p+qoh - :new.line_units;
        where produc.p_code = :new.p_code;
    end;

这会引发一个不太友好的错误消息,例如:

ORA-02290: check constraint (MYSCHEMA.PROD_QOH_CHECK) violated

您可以在触发器中捕获它并给出您想要的消息:

create or replace trigger trg_prod_qoh_on_line_add
    before insert on line
    for each row
    begin
        update product
        set p_qoh = p+qoh - :new.line_units;
        where produc.p_code = :new.p_code;
    exception
        when others then
            if sqlerrm like 'ORA-02291:%(MYSCHEMA.PROD_QOH_CHECK)%' then
                raise_application_error(-20202,'Insufficient quantity on hand');
            else
                raise;
            end if;
    end;

Now if we re-run the 2 user scenario above:

user1> insert into line (p_code, line_units) values ('X', 7);

user2> insert into line (p_code, line_units) values ('X', 8);

user1> commit;

At this point user2's insert fails with the error message:

ORA-20202: Insufficient quantity on hand
于 2012-06-18T10:04:25.833 回答