Postgresql:条件付きで一意の制約


116

テーブルの一部でのみ列に一意性を適用する制約を追加したいと思います。

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

上記のWHERE部分は希望的な考えです。

これを行う方法はありますか?それともリレーショナル図面に戻るべきですか?


2
一般的に行われます。「部分固有インデックス」を参照してください
クレイグリンガー、

11
@yvesonlineいいえ、それは通常の一意制約です。ポスターは部分的に一意の制約を求めています。
クレイグリンガー

回答:


186

PostgreSQLは部分的(つまり、条件付き)UNIQUE制約を定義していません。ただし、部分的に一意のインデックスを作成できます。PostgreSQLは一意のインデックスを使用して一意の制約を実装しているため、効果は同じで、にリストされている制約は表示されません。information_schema

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

部分インデックスを参照してください。


24
素晴らしい!「制約」が制約として表示されないが、それでも望ましいエラーが発生するというERROR: duplicate key value violates unique constraint "stop_myc"
直感

7
これは、部分的に一意のフィールドであるFK参照の作成を許可しないことに注意してください。
ffflabs 2017年

11
また、このインデックスの効果は延期できないことにも注意してください。一括更新を実行する必要がある場合、制約の場合のようにステートメントの後や遅延可能な制約の場合のようにトランザクションの後にではなく、すべての行の後で一意性がチェックされるため、問題が発生する可能性があります。
sage88 2018年

37

PGは部分的(つまり、条件付き)UNIQUE制約を定義しないと既に述べられています。また、ドキュメントには、一意の制約をテーブルに追加する好ましい方法は一意のインデックスであると記載されていますADD CONSTRAINT

テーブルに一意性制約を追加するための推奨される方法は、ALTER TABLE ... ADD CONSTRAINTです。インデックスを使用して一意の制約を適用することは、直接アクセスしてはならない実装の詳細と考えることができます。ただし、一意の列に手動でインデックスを作成する必要がないことに注意してください。これにより、自動的に作成されたインデックスが複製されます。

除外制約を使用してそれを実装する方法があります(このソリューションについては@dukelionに感謝)

あなたの場合は次のようになります

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

そのアプローチでは、インデックスメソッドを定義するために "using"を使用しないので、非常に遅くなるか、postgresがそれにデフォルトインデックスを作成しますか?その方法は標準的な選択ですが、これ以上の選択はありません!私はあなたがその選択をより良いものにするためにインデックス付きの「using」節が必要になると思います。
Natan Medeiros、2018

10
速度は遅くなりますが、excludeソリューションの利点は、延期可能であることです(デフォルトでは、ステートメントの最後まで延期されます)。対照的に、受け入れられた一意のインデックスソリューションは延期できません(行が変更されるたびにチェックされます)。そのため、アトミック更新ステートメントの最後で違反がなくても、更新中の手順が一意制約に違反するため、一括更新はしばしば不可能です。
sage88 2018年

1
このメモは2015
Raniz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.