DECLARE
ブロックにPRAGMA AUTONOMOUS_TRANSACTION
を使用せずにCOMMIT
を使用することはできません。個々の文のすべての行は、その変更を完了しなければなりません - データベースが行レベルのトリガーにコミット許可された場合は他の人が評価されていたとのユニットとして文を乱す前に
することは、これは、ステートメント内の行の一部をコミット可能にすることができます一緒に約束してください。
このトリガーでAUTONOMOUS_TRANSACTIONを使用する場合は、オープン・トランザクション内の他のアクティブなDML変更とは独立したトランザクションで、トリガーが新規UPDATE
秒、DELETE
秒などを実行できるようになります。
ただし、TRIGGER
はDML
を実際に実行しておらず、読み込みも行っていないため、COMMIT
はまったく必要ありません。あなたがする必要があるのは、以下のようにCOMMIT
をドロップすることだけです。
CREATE OR REPLACE TRIGGER my_trig
BEFORE DELETE OR INSERT OR UPDATE ON empcopy
FOR EACH ROW
WHEN (NEW.EID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END;
/
ただし、他にもいくつかの変更点があります。他のトリガーとして
もNEW
値を変更することができ、あなただけの最終状態を記録するために、このAFTER TRIGGER
することを検討することがあります。 DELETE
sがすべてNULL
:NEW.EID
を持つことになりますので、
また、このトリガは、任意のDELETE
秒を記録しません。ログDELETE
が意図されていない場合はAFTER DELETE
を削除するか、CASE WHEN DELETING
ステートメントを使用してDELETE
を別々に処理することをお勧めします。
CREATE OR REPLACE TRIGGER MY_TRIG
AFTER DELETE OR INSERT OR UPDATE ON EMPCOPY
FOR EACH ROW
DECLARE
SAL_DIFF NUMBER;
BEGIN
CASE WHEN DELETING
THEN
DBMS_OUTPUT.put_line('Log the delete here if you want.');
WHEN (:NEW.EID > 0)
THEN
SAL_DIFF := COALESCE(:NEW.SALARY, 0) - COALESCE(:OLD.SALARY, 0);
DBMS_OUTPUT.put_line('Old salary: ' || :OLD.SALARY);
DBMS_OUTPUT.put_line('New salary: ' || :NEW.SALARY);
DBMS_OUTPUT.put_line('Salary difference: ' || SAL_DIFF);
ELSE NULL;
END CASE;
END;
/
また、DBMS_OUTPUTは一時的なログです。 EMPCOPY
の変更の記録をより永続的に保持したい場合は、監査証跡やFGAなど、データの変更追跡を自動化して制御するためのツールが用意されています。
EDIT:下記の例。
テストテーブルを作成します。
CREATE TABLE EMPCOPY(
EID NUMBER NOT NULL,
SALARY NUMBER
);
Table EMPCOPY created.
その後、トリガーを作成します。
CREATE OR REPLACE TRIGGER MY_TRIG
AFTER DELETE OR INSERT OR UPDATE ON EMPCOPY
FOR EACH ROW
DECLARE
SAL_DIFF NUMBER;
BEGIN
CASE WHEN DELETING
THEN
DBMS_OUTPUT.put_line('Log the delete here if you want.');
WHEN (:NEW.EID > 0)
THEN
SAL_DIFF := COALESCE(:NEW.SALARY, 0) - COALESCE(:OLD.SALARY, 0);
DBMS_OUTPUT.put_line('Old salary: ' || :OLD.SALARY);
DBMS_OUTPUT.put_line('New salary: ' || :NEW.SALARY);
DBMS_OUTPUT.put_line('Salary difference: ' || SAL_DIFF);
ELSE NULL;
END CASE;
END;
/
Trigger MY_TRIG compiled
そして、それをテストします。http:非常によく似た質問があったよう
SQL> --Should not log, EMPID is not greater than zero.
SQL> INSERT INTO EMPCOPY VALUES (-13, 50000);
1 row inserted.
SQL> --Should log, EMPID is greater than zero.
SQL> INSERT INTO EMPCOPY VALUES (1919, 75000);
Old salary:
New salary: 75000
Salary difference: 75000
1 row inserted.
SQL> -- The statement you provided. This should log for EMPID=1919 but not EMPID=-13
SQL> update empcopy
2 set salary=salary+5000;
Old salary: 75000
New salary: 80000
Salary difference: 5000
2 rows updated.
SQL> -- This should log a PLACEHOLDER value for each row on delete.
SQL> DELETE FROM EMPCOPY;
Log the delete here if you want.
Log the delete here if you want.
2 rows deleted.
はルックス: //stackoverflow.com/questions/22668507/oracle-trigger-ora-04098-trigger-is-invalid-and-failed-re-validation – Debangshu
このソリューションでは動作しません。 –
@Jaskunwarsinghこの回答は完全な実例で更新されました。提供されている例を実行し、エラーが発生した場合はお知らせください。また、あなたのオラクルのバージョンを含むことはしばしば役に立ちます。 – alexgibbs