Kilka punktów. Po pierwsze, nadużywasz autonomicznej pragma transakcyjnej. Jest przeznaczony do oddzielnych transakcji, które musisz zatwierdzić lub wycofać niezależnie od głównej transakcji. Używasz go do wycofania głównej transakcji - i nigdy nie zatwierdzasz, jeśli nie ma błędu.
A te „nieprzewidziane konsekwencje”, o których ktoś wspomniał? Jednym z nich jest to, że licznik zawsze zwraca 0. Usuń pragmę, ponieważ jest ona niewłaściwie używana, a licznik zwróci prawidłową wartość.
Inną rzeczą jest brak zatwierdzeń lub cofnięć w wyzwalaczach. Zgłoś błąd i pozwól kodowi sterującemu zrobić to, co musi. Wiem, że wycofania były spowodowane pragmą. Tylko nie zapomnij o ich usunięciu, gdy usuniesz pragmę.
Dla mnie działa następujący wyzwalacz:
CREATE OR REPLACE TRIGGER trg_mytable_biu
BEFORE INSERT OR UPDATE ON mytable
FOR EACH ROW
WHEN (NEW.TYPEB = 'Bert') -- Don't even execute unless this is Bert
DECLARE
L_COUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO L_COUNT
FROM MYTABLE
WHERE ARTICLE = :NEW.ARTICLE
AND TYPEB = :NEW.TYPEB;
IF L_COUNT > 0 THEN
RAISE_APPLICATION_ERROR( -20001, 'Bert already exists!' );
ELSIF :NEW.STOCK_COUNT > 1 THEN
RAISE_APPLICATION_ERROR( -20001, 'Can''t insert more than one Bert!' );
END IF;
END;
Jednak nie jest dobrym pomysłem, aby wyzwalacz w tabeli miał osobny dostęp do tej tabeli. Zwykle system nawet na to nie pozwala -- ten wyzwalacz w ogóle się nie uruchomi, jeśli zostanie zmieniony na „po”. Jeśli jest to dozwolone do wykonania, nigdy nie można być pewnym uzyskanych wyników – jak już się dowiedziałeś. Właściwie jestem trochę zaskoczony, że powyższy wyzwalacz działa. Czułbym się nieswojo, używając go w prawdziwej bazie danych.
Najlepsza opcja, gdy wyzwalacz musi dostęp do tabeli docelowej polega na ukryciu tabeli za widokiem i napisaniu wyzwalacza „zamiast” w widoku. To wyzwalacz może uzyskać dostęp do tabeli, ile tylko chce.