いくつかのポイント。まず、自律トランザクションプラグマを誤用しています。これは、メイントランザクションとは独立してコミットまたはロールバックする必要がある個別のトランザクションを対象としています。これを使用してメイントランザクションをロールバックしています。エラーがない場合はコミットしません。
そして、誰かが言及したそれらの「予期しない結果」?そのうちの1つは、カウントが常に0を返すことです。したがって、プラグマは誤用されているため削除し、カウントが適切な値を返すようにします。
もう1つは、トリガー内にコミットまたはロールバックがないことです。エラーを発生させ、制御コードに必要な処理を実行させます。ロールバックはプラグマによるものだと私は知っています。プラグマを削除するときは、それらを削除することを忘れないでください。
次のトリガーが機能します:
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;
ただし、テーブルのトリガーがそのテーブルに個別にアクセスすることはお勧めできません。通常、システムはそれを許可しません。このトリガーは、「後」に変更された場合、まったく実行されません。実行が許可されている場合、すでにわかっているように、得られた結果を確認することはできません。実際、上記のトリガーが機能することに少し驚いています。実際のデータベースで使用するのは不安です。
トリガーが必要である場合の最良のオプション ターゲットテーブルへのアクセスは、ビューの背後にあるテーブルを非表示にし、ビューに「代わりの」トリガーを書き込むことです。 それ トリガーは必要なすべてのテーブルにアクセスできます。