Pár bodů. Za prvé, zneužíváte pragma autonomních transakcí. Je určen pro samostatné transakce, které musíte potvrdit nebo vrátit zpět nezávisle na hlavní transakci. Používáte jej k vrácení hlavní transakce – a nikdy se nepotvrdíte, pokud nedojde k chybě.
A ty "nepředvídané následky", které někdo zmínil? Jedním z nich je, že váš počet vždy vrátí 0. Odstraňte tedy pragma obojí, protože je zneužíváno, a tak počet vrátí správnou hodnotu.
Další věc je, že v rámci spouštěčů nemáte potvrzení nebo vrácení zpět. Vyvolejte chybu a nechte řídicí kód udělat, co potřebuje. Vím, že návraty byly kvůli pragmatu. Jen je nezapomeňte odstranit, když odstraníte pragma.
Funguje mi následující spouštěč:
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;
Není však dobrý nápad, aby spouštěč na tabulce samostatně přistupoval k této tabulce. Obvykle to systém ani nepovolí -- tento trigger se vůbec nespustí, pokud se změní na "po". Pokud je povoleno provést, nikdo si nemůže být nikdy jistý dosaženými výsledky - jak jste již zjistili. Vlastně jsem trochu překvapený, že spoušť výše funguje. Cítil bych se nesvůj používat to ve skutečné databázi.
Nejlepší možnost, když spouštěč musí přístup k cílové tabulce je skrýt tabulku za pohled a napsat na pohled spouštěč „místo“. To trigger může přistupovat k tabulce, jak chce.