/ / PL / SQL Instrukcja warunkowa za pomocą dwóch tabel w wyzwalaczu - sql, oracle, join, plsql, triggers

Instrukcja warunkowa PL / SQL za pomocą dwóch tabel w wyzwalaczu - sql, oracle, join, plsql, triggers

Pracuję nad prostym wyzwalaczem, który aktualizujeIlość na rękę produktu przy dodawaniu nowej linii faktury. Sprawiłem, że działa dobrze; ale zaczynam myśleć, że w praktycznym zastosowaniu byłoby rozsądne sprawdzenie, czy QOH jest wystarczający przed zezwoleniem na aktualizację. Jestem pewien, że mógłbym napisać osobny wyzwalacz, ale chciałbym zobaczyć, czy możliwe jest dołączenie dwóch tabel dla warunkowego oświadczenia w ramach wyzwalacza.

To jest tak daleko, jak to osiągnąłem: dodanie instrukcji SELECT gdziekolwiek tam jest, powoduje, że całe piekło się rozpada, więc jestem trochę zakłopotany, jak mogę zadeklarować PRODUCT.P_QOH przed wywołaniem warunkowego.

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;
/

Nie jest to dla mnie poważny problem, ponieważ powiedziałem, że prawdopodobnie jest inny sposób, zaczynam się uczyć tych rzeczy i chciałbym zobaczyć, co jest możliwe, dziękuję za pomoc.

Odpowiedzi:

3 dla odpowiedzi № 1

Wchodzisz na niebezpieczne terytorium, próbując egzekwować takie reguły za pomocą wyzwalaczy. Rozwiązanie, o które prosisz, to:

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;

Jednak tak jest nie bezpieczne rozwiązanie w systemie z więcej niż jednym współbieżnym użytkownikiem. Załóżmy, że produkt "X" ma p_qoh = 10, a następnie 2 użytkowników:

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;

Obie sesje zobaczą, że "X" ma p_qoh = 10, więc oba powiodą się, a product.p_qoh skończy jako -5. Wszystko jest zepsute!

Bezpiecznym rozwiązaniem byłoby utworzenie ograniczenia kontrolnego dla produktu:

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

Teraz wyzwalacz może być po prostu:

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;

Podniesie to mniej przyjazny komunikat o błędzie, taki jak:

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

Możesz uwięzić to w swoim wyzwalaczu i podać żądaną wiadomość:

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;

Teraz, jeśli ponownie uruchomimy scenariusz dla 2 użytkowników powyżej:

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

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

user1> commit;

W tym momencie insert użytkownika 2 nie powiedzie się z komunikatem o błędzie:

ORA-20202: Insufficient quantity on hand