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