Een paar punten. Ten eerste misbruik je het autonome transactiepragma. Het is bedoeld voor afzonderlijke transacties die u onafhankelijk van de hoofdtransactie moet vastleggen of terugdraaien. Je gebruikt het om de hoofdtransactie terug te draaien -- en je pleegt nooit als er geen fout is.
En die "onvoorziene gevolgen" die iemand noemde? Een daarvan is dat je telling altijd 0 retourneert. Dus verwijder het pragma zowel omdat het wordt misbruikt als de telling een juiste waarde retourneert.
Een ander ding is dat je geen commits of rollbacks hebt binnen triggers. Geef een foutmelding en laat de controlerende code doen wat hij moet doen. Ik weet dat de terugdraaiingen waren vanwege het pragma. Vergeet ze niet te verwijderen wanneer u het pragma verwijdert.
De volgende trigger werkt voor mij:
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;
Het is echter geen goed idee voor een trigger op een tafel om afzonderlijk toegang te krijgen tot die tabel. Meestal staat het systeem het niet eens toe -- deze trigger wordt helemaal niet uitgevoerd als deze wordt gewijzigd in "na". Als het is toegestaan om uit te voeren, kan men nooit zeker zijn van de verkregen resultaten - zoals u al ontdekte. Eigenlijk ben ik een beetje verbaasd dat de bovenstaande trigger werkt. Ik zou me ongemakkelijk voelen als ik het in een echte database zou gebruiken.
De beste optie wanneer een trigger moet toegang tot de doeltabel is om de tabel achter een weergave te verbergen en een "in plaats van" trigger op de weergave te schrijven. Dat trigger heeft toegang tot de tafel zoveel hij wil.