11

私は2つのテーブルを持っています:

person:
    id serial primary key,
    name varchar(64) not null

task:
    tenant_id   integer not null references person (id) on delete cascade,
    customer_id integer not null references person (id) on delete restrict

(それよりも多くの列がありますが、残りは質問に関係ありません。)

task問題は、テナントが削除されたときにカスケード削除したいことですperson。ただし、テナントと顧客が同一人物の場合、customer_id外部キー制約により削除が制限されます。

私の質問には2つの部分があります:

  1. 2 番目の外部キーを一時的に無効にすることが唯一の選択肢ですか?
  2. もしそうなら、PostgreSQLでそれを行うにはどうすればよいですか?
4

1 に答える 1

14

事実上、矛盾するルールで競合状態を作成します。

私の最初の衝動は、DEFERRED制約が役立つかどうかを確認することでした。しかし、それは何の違いもないということは理にかなっています。

スクリプトで最初にCREATE TABLE来る FK 制約がこの競争の勝者であることがわかりました。が最初に来る場合ON DELETE CASCADE、削除はカスケードされ、ON DELETE RESTRICT最初に来る場合、操作は中止されます。

SQL Fiddleのデモを検討してください。

oidこれは、カタログ テーブルの小さい方と相関しているようですpg_constraint

SELECT oid, * FROM pg_constraint WHERE conrelid = 'task'::regclass

しかし、あなたのフィードバックは、これが原因ではないことを示しています。たぶんpg_attribute.attnumレースを決める。いずれにせよ、それが文書化された動作でない限り、次のメジャー バージョンでそのようにとどまることに依存することはできません。pgsql-general@postgresql.org に質問を投稿する価値があるかもしれません。

それとは独立して、他のCASCADE行を考慮する必要があります。ケースを示す 別のSQL Fiddle 。tasktenant_idcustomer_idpersoncustomer_idperson

制約を無効にする方法は?

あなたの最善の策は、それを落として再作成することです。参照整合性を損なわないように、トランザクション内ですべて実行してください。

BEGIN;

ALTER TABLE task DROP CONSTRAINT task_customer_id_fkey;

DELETE FROM person WHERE id = 3;

ALTER TABLE task ADD CONSTRAINT task_customer_id_fkey
FOREIGN KEY (customer_id) REFERENCES person (id) ON DELETE RESTRICT;

COMMIT;

これはテーブルを排他的にロックするため、マルチユーザー環境での日常的な使用には適していません。

制約の名前をどうやって知りましたか? pg_constraint上記のように取得しました。最初は明示的な制約名を使用する方が簡単かもしれません:

CREATE TEMP TABLE task (
    customer_id integer NOT NULL
   ,tenant_id integer NOT NULL REFERENCES person (id) ON DELETE CASCADE
   ,CONSTRAINT task_customer_id_fkey FOREIGN KEY (customer_id)
    REFERENCES person (id) ON DELETE RESTRICT
);

もあります

ALTER TABLE task DISABLE trigger ALL;

詳細については、こちらのマニュアルを参照してください。しかし、それはすべてのトリガーを無効にします。単一の FK 制約を実装するためにシステムによって作成されたトリガーのみを無効にしようとしてもうまくいきませんでした。

他の選択肢は、トリガーまたはルールを使用して体制を実装することです。それは問題なく機能しますが、それらは外部キーほど厳密には適用されません。

于 2013-02-21T17:56:53.690 に答える