PostgreSQL でトリガーを使用する方法を学んでいますが、次のコードで問題が発生します。
CREATE OR REPLACE FUNCTION checkAdressen() RETURNS TRIGGER AS $$
DECLARE
adrCnt int = 0;
BEGIN
SELECT INTO adrCnt count(*) FROM Adresse
WHERE gehoert_zu = NEW.kundenId;
IF adrCnt < 1 OR adrCnt > 3 THEN
RAISE EXCEPTION 'Customer must have 1 to 3 addresses.';
ELSE
RAISE EXCEPTION 'No exception';
END IF;
END;
$$ LANGUAGE plpgsql;
すべてのテーブルを新しく作成した後、この手順でトリガーを作成して、すべて空にします。ただし、count(*)上記のコードの関数は 1 を返しますSELECT count(*) FROM adresse;。PL/pgSQL の外部で実行すると、0 が返されます。FOUND変数を使用してみましたが、常に true です。
さらに奇妙なことに、いくつかの値をテーブルに挿入し、それらを再度削除して再び空にすると、コードは意図したとおりに機能し、0count(*)を返します。なしよりも句。WHERE gehoert_zu = NEW.kundenIdcount(*)WHERE
- 編集:
手順の使用方法の例を次に示します。
CREATE TABLE kunde (
kundenId int PRIMARY KEY
);
CREATE TABLE adresse (
id int PRIMARY KEY,
gehoert_zu int REFERENCES kunde
);
CREATE CONSTRAINT TRIGGER adressenKonsistenzTrigger AFTER INSERT ON Kunde
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE checkAdressen();
INSERT INTO kunde VALUES (1);
INSERT INTO adresse VALUES (1,1);
DEFERRABLE INITIALLY DEFERREDパーツを間違えているようです。トリガーは最初のINSERTステートメントの後に実行されると想定しましたが、挿入はブロック内にありませBEGIN;んが、2番目のステートメントの後に発生します。COMMIT;
PostgreSQL のドキュメントによると、そのようなブロック内にない場合、挿入は毎回自動的にコミットされるためadresse、最初のINSERTステートメントがコミットされたときにエントリが存在しないはずです。
誰かが私の間違いを指摘できますか?
- 編集:
トリガーDEFERRABLE INITIALLY DEFERREDは問題なく動作しているようです。私の間違いは、BEGIN- COMMIT-Block を使用していないため、各挿入が独自のトランザクションで実行され、トリガーが毎回実行されると仮定することでした。
ただし、BEGIN-がなくても、COMMITすべての挿入が 1 つのトランザクションにまとめられ、その後トリガーが実行されます。この動作を考えると、BEGIN-を使用するポイントは何COMMITですか?