Et par punkter. For det første misbruger du pragmaen for autonome transaktioner. Det er beregnet til separate transaktioner, du skal forpligte eller rulle tilbage uafhængigt af hovedtransaktionen. Du bruger den til at rulle hovedtransaktionen tilbage -- og du forpligter dig aldrig, hvis der ikke er nogen fejl.
Og de "uforudsete konsekvenser", som nogen nævnte? En af dem er, at din optælling altid returnerer 0. Så fjern pragmaen, både fordi den bliver misbrugt, og så vil optællingen returnere en ordentlig værdi.
En anden ting er, at du ikke har commits eller rollbacks inden for triggere. Ret en fejl, og lad den kontrollerende kode gøre, hvad den skal gøre. Jeg ved, at tilbagefaldene var på grund af pragmaen. Bare glem ikke at fjerne dem, når du fjerner pragmaen.
Følgende trigger virker for mig:
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;
Det er dog ikke en god idé for en trigger på et bord at få adgang til den tabel separat. Normalt vil systemet ikke engang tillade det -- denne trigger vil slet ikke udføres, hvis den ændres til "efter". Hvis den får lov til at udføre, kan man aldrig være sikker på de opnåede resultater - som du allerede har fundet ud af. Faktisk er jeg lidt overrasket over, at udløseren ovenfor virker. Jeg ville føle mig utryg ved at bruge den i en rigtig database.
Den bedste mulighed, når en trigger skal adgang til måltabellen er at skjule tabellen bag en visning og skrive en "i stedet for" trigger på visningen. Det trigger kan få adgang til tabellen alt, hvad den vil.