トリガーを介してこのようなルールを適用しようとすると、危険な領域に入ります。あなたが求めている解決策は次のとおりです。
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;
上記の 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 の挿入は次のエラー メッセージで失敗します。
ORA-20202: Insufficient quantity on hand