Няколко точки. Първо, вие злоупотребявате с прагмата за автономна транзакция. Предназначен е за отделни транзакции, които трябва да извършите или върнете назад независимо от основната транзакция. Използвате го за връщане назад на основната транзакция -- и никога не се ангажирате, ако няма грешка.
И онези "непредвидени последствия", които някой спомена? Едно от тях е, че вашият брой винаги връща 0. Така че премахнете прагмата, защото се използва неправилно и така броячът ще върне правилна стойност.
Друго нещо е да нямате ангажименти или връщания назад в тригерите. Повишете грешка и оставете управляващия код да направи това, което трябва. Знам, че връщанията бяха заради прагмата. Само не забравяйте да ги премахнете, когато премахнете pragma.
Следният тригер работи за мен:
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;
Въпреки това не е добра идея тригер на таблица да има отделен достъп до тази таблица. Обикновено системата дори няма да го позволи - този тригер изобщо няма да се изпълни, ако бъде променен на "след". Ако е позволено да се изпълни, човек никога не може да бъде сигурен в получените резултати - както вече разбрахте. Всъщност съм малко изненадан, че тригерът по-горе работи. Бих се почувствал неудобно да го използвам в истинска база данни.
Най-добрият вариант, когато тригерът трябва достъп до целевата таблица е да скриете таблицата зад изглед и да напишете тригер "вместо" в изгледа. Това trigger може да има достъп до таблицата, колкото иска.