13

販売に関連して、あるユーザーから残されたフィードバックのために、別のユーザーのために、一意の制約を持つテーブルがあります。

ALTER TABLE feedback
ADD CONSTRAINT unique_user_subject_and_sale
UNIQUE (user_id, subject_id, sale_id)

これにより、誤って重複したフィードバックの行を取得することがなくなります。

現在、エラーが残ったフィードバックを完全に削除し、ユーザーが再び残したままにすることがあります。論理的な削除に変更します。

ALTER TABLE feedback
ADD COLUMN deleted_at timestamptz

の場合deleted_at IS NOT NULLは、フィードバックが削除されたと考えてください。ただし、DB にはまだ監査証跡があります (おそらくサイト管理者にはゴースト アウトされていることが示されます)。

このように論理的な削除を使用しているときに、一意の制約を維持するにはどうすればよいでしょうか? 集計チェックを行うより一般的なCHECK()制約を使用せずに可能ですか (このようなチェック制約を使用したことはありません)。

制約に WHERE 句を追加する必要があるようです。

4

3 に答える 3

28

後で編集された一意のインデックス。

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null
ON feedback(user_id, subject_id, sale_id)
WHERE deleted_at IS NULL

一意のインデックスには、問題を引き起こす可能性のある少なくとも 2 つの副作用があります。

  1. 他のテーブルでは、「フィードバック」を参照する外部キー制約を設定できません。primary key外部キー参照では、列の組み合わせをまたはとして宣言する必要がありますunique
  2. 一意のインデックスでは、「deleted_at」タイムスタンプのみが異なる複数の行が許可されます。したがって、次の例のような行になる可能性があります。これが問題になるかどうかは、アプリケーションに依存します。

user_id  subject_id  sale_id  deleted_at
--
1        1           1        2012-01-01 08:00:01.33
1        1           1        2012-01-01 08:00:01.34
1        1           1        2012-01-01 08:00:01.35

PostgreSQL は、この種のインデックスを部分インデックスとして文書化しています。他のプラットフォームでは、別の用語が使用されます。フィルター処理されたインデックスは 1 つです。部分インデックスのペアを使用すると、問題をある程度制限できます。

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null
ON feedback(user_id, subject_id, sale_id)
WHERE deleted_at IS NULL

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_not_null
ON feedback(user_id, subject_id, sale_id)
WHERE deleted_at IS NOT NULL

しかし、特に外部キーに関する潜在的な問題を考えると、これほど面倒なことをする理由はないと思います。あなたのテーブルがこのように見える場合

create table feedback (
  feedback_id integer primary key,
  user_id ...
  subject_id ...
  sale_id ...
  deleted_at ...
  constraint unique_user_subj_sale 
    unique (user_id, subject_id, sale_id)
);

必要なのは、{user_id、subject_id、sale_id} に対する一意の制約だけです。さらに、完全な削除を行う代わりに、すべての削除で「deleted_at」列を使用することを検討することもできます。

于 2012-11-06T23:04:18.423 に答える
8

PostgreSQL のドキュメントでは、制約の代わりに一意のインデックスを使用しないようにアドバイスされているにもかかわらず (要点が制約を持つ場合)、実行できるようです。

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale
ON feedback(user_id, subject_id, sale_id)
WHERE deleted_at IS NULL
于 2012-11-06T23:03:29.610 に答える