11

Postgres テーブルには、とstatusの 2 つの値しかとれない列があります。ActiveInactive

列の 1 つの名前はuseridです。テーブルには同じ行を複数持つことができますuseridが、最大でもそのうちの 1 つに を含めることができますstatus = 'Active'。に従って、1つだけ必要な場合と不要な場合がstatusありActiveますuserid。この条件で制約を作成するにはどうすればよいですか? Postgres のドキュメントからヘルプが見つかりませんでした。

4

1 に答える 1

17

status本当にあるはずbooleanです。より安く、よりきれいに。

どちらの方法でも、部分的な一意のインデックスを使用してルールを課すことができます。

status = 'Active' テーブル全体で 0 行または 1 行を許可するには:

CREATE UNIQUE INDEX tbl_active_uni ON tbl (status)
WHERE status = 'Active';

status = 'Active' peruseridで0 行または 1 行を許可するにuseridは、インデックス付きの列を作成します。

CREATE UNIQUE INDEX tbl_userid_active_uni ON tbl (userid)
WHERE status = 'Active';

userid IS NULL2 つの NULL 値が等しいとは見なされないため、一意の違反はトリガーされないことに注意してください。この場合、設定useridする必要があります。NOT NULL

制約ではなくインデックスを使用する理由

コメントで質問に対処する: これはインデックスであり、CONSTRAINT.

最初のケースのインデックスはtinyで、行を 1 つ保持するか、保持しません。
2 番目のケースのインデックスは、既存の ごとに 1 つの行を保持しますが、クリーンで安全であることに加えて、useridこれが最も安価で最速の方法です。これを高速化するには、いずれにしても他の行をチェックするためのインデックスが必要です。

CHECK少なくともクリーンで信頼できる方法では、他の行で制約チェックを行うことはできません。この場合、私が絶対にお勧めしない方法があります。

UNIQUE制約を使用する場合(これも内部的に一意のインデックスで実装されています!)、それをpartial(userid, status)にすることはできず、すべての組み合わせが一意になるように強制されます。ケースを除くすべてのケースで作業する場合、これを引き続き使用できます。しかし、実際には、すべての行を含むはるかに大きなインデックスが必要になります。status IS NULL'Active'

于 2015-12-28T14:46:06.887 に答える