Ett par punkter. För det första missbrukar du pragman för autonoma transaktioner. Den är avsedd för separata transaktioner som du behöver utföra eller återställa oberoende av huvudtransaktionen. Du använder den för att återställa huvudtransaktionen -- och du förbinder dig aldrig om det inte finns något fel.
Och de där "oförutsedda konsekvenserna" som någon nämnde? En av dem är att din räkning alltid returnerar 0. Så ta bort pragman både för att den missbrukas och så kommer räkningen att returnera ett korrekt värde.
En annan sak är att inte ha commits eller rollbacks inom triggers. Skapa ett fel och låt den kontrollerande koden göra vad den behöver göra. Jag vet att tillbakadragningarna berodde på pragman. Glöm bara inte att ta bort dem när du tar bort pragman.
Följande trigger fungerar för 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 är dock inte en bra idé för en utlösare på ett bord att separat komma åt den tabellen. Vanligtvis tillåter systemet inte ens det -- denna utlösare kommer inte att köras alls om den ändras till "efter". Om det är tillåtet att exekvera, kan man aldrig vara säker på de resultat som erhållits - som du redan har upptäckt. Jag är faktiskt lite förvånad över att triggern ovan fungerar. Jag skulle känna mig obekväm med att använda den i en riktig databas.
Det bästa alternativet när en utlösare måste komma åt måltabellen är att gömma tabellen bakom en vy och skriva en "istället för" trigger på vyn. Det trigger kan komma åt tabellen allt den vill.