18

次のように、必須の参加をチェックする機能があります。

CREATE FUNCTION member_in_has_address()
RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (SELECT *
       FROM address a, member_details b
       WHERE b.member_id = a.member_id);
END;
$$  LANGUAGE plpgsql;

次に、CHECK 制約から呼び出されます

ALTER TABLE member_details
 ADD CONSTRAINT member_in_has_address_check
  CHECK (member_in_has_address());

標準 SQL で遅延可能な制約を作成するには、次のようにします。

ALTER TABLE member_details
 ADD CONSTRAINT member_in_has_address_check
  INITIALLY DEFERRED
  CHECK (member_in_has_address()); 

PostgreSQL で同じことを行うにはどうすればよいですか?

4

4 に答える 4

26

PostgreSQL では、他の RDBMS と同じ方法で制約を延期できますが、現在のバージョン (9.2) では、UNIQUE、PRIMARY KEY、EXCLUDE、および REFERENCES のみを延期できます。this pageマニュアルからの抜粋:

DEFERRABLE
NOT DEFERRABLE

これは、制約を延期できるかどうかを制御します。延期できない制約は、すべてのコマンドの直後にチェックされます。遅延可能な制約のチェックは、トランザクションの終了まで延期できます (SET CONSTRAINTS コマンドを使用)。NOT DEFERRABLE がデフォルトです。現在、UNIQUE、PRIMARY KEY、EXCLUDE、および REFERENCES (外部キー) 制約のみがこの句を受け入れます。NOT NULL および CHECK 制約は延期できません。

INITIALLY IMMEDIATE
INITIALLY DEFERRED

制約が遅延可能である場合、この句は、制約をチェックするデフォルトの時間を指定します。制約が INITIALLY IMMEDIATE の場合、各ステートメントの後にチェックされます。これがデフォルトです。制約が INITIALLY DEFERRED の場合、トランザクションの最後にのみチェックされます。制約チェック時間は、SET CONSTRAINTS コマンドで変更できます。

すべてのメンバーにアドレスがあるかどうかを確認するために、現在の制約の代わりにmember_detailstoから単純な遅延外部キーを作成できます。address

更新: 2 つの外部キーを作成する必要があります。address(member_id)からまでの通常の 1 つmember_details(member_id)。もう 1 つは から まで延期されmember_details(member_id)ましたaddress(member_id)

この 2 つの外部キーを使用すると、次のことが可能になります。

  1. でメンバーを作成しますmember_details
  2. address手順 1 からメンバーのアドレスを作成する
  3. コミット (エラーなし)

また

  1. でメンバーを作成しますmember_details
  2. コミットします (そして、延期された外部キーからエラーを取得します)。
于 2013-05-01T18:02:55.777 に答える
3

クエリをトランザクションでラップし、少なくとも 1 つのアドレスが必要な場合は、遅延外部キーと遅延制約トリガーを使用します。

CREATE CONSTRAINT TRIGGER member_details_address_check_ins
  AFTER INSERT ON member_details
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE member_details_address_check_ins();

ALTER TABLE address
ADD CONSTRAINT address_member_details_member_id_fkey
FOREIGN KEY (member_id) REFERENCES member_details(member_id)
ON UPDATE NO ACTION ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED;

CREATE CONSTRAINT TRIGGER address_member_details_check_del
  AFTER DELETE ON address
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE address_member_details_check_del();

-- also consider the update cases for the inevitable merge of duplicate members.

別の注意点として、正規化されていてきれいですが、アドレスと電子メールなどの連絡先の詳細を別のアドレス テーブルに入れると、非常にカラフルな UI/UX の問題が発生することがあります。たとえば、訓練を受けていない秘書が、会社 A の上司の連絡先の 1 つが会社 B に変わったときに会社と住所をすべて変更しました。

とにかく、fwiw、私は通常、連絡先と同じテーブル、つまり address1、address2、email1、email2 などにこの情報を格納する方が便利であることがわかりました。これにより、他のさまざまな理由で他のことがより簡単になります-つまり、あなたが調べているようなチェックを実行しています。そのような情報を 2 つ以上保存したいという非常にまれなケースは、実際には、手間をかけるだけの価値はありません。

于 2013-05-02T14:32:33.923 に答える