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.kundenId
count(*)
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
ですか?