日付範囲の一意性制約


15

pricesこれらの列を持つテーブルを考えてみましょう。

id         integer primary key
product_id integer -- foreign key
start_date date not null
end_date   date not null
quantity   integer
price      numeric

データベースには、日付範囲内の特定の数量で1つの価格しか持てないというルールを適用したいのですが(を介してwhere <date> BETWEEN start_date AND end_date)。

この種の範囲ベースの制約は実行可能ですか?

回答:


23

はい、EXCLUDE制約の一般化であるUNIQUE制約を使用できます。

ALTER TABLE prices 
  ADD CONSTRAINT unique_price_per_product_quantity_daterange
    EXCLUDE  USING gist
    ( product_id WITH =, 
      quantity WITH =, 
      daterange(start_date, end_date, '[]') WITH &&   -- this is the crucial
    );

制約は次のように解釈できます:

同じproduct_id、同じを持つ2つの行を許可しないquantity、重複する(&&)日付範囲。

'[]'は、必要なすべてを含む日付範囲[)用です(デフォルトは範囲タイプ用です)。

範囲タイプの制約に関するドキュメントを参照してください。(おそらく、これをインストールするデータベースごとに)を実行して、拡張機能を追加する必要があります。

CREATE EXTENSION btree_gist;

これはすごい。排他的な下限なのでまったく同じだとdaterangeは思いませんが、それは簡単に修正できます。列タイプを使用するようにデータを実際に移行する必要がありますか(それが良い場合は別の質問にすることができます)、またはこの2列のことは合理的ですか?daterange
スパイク

よく覚えていれば、包含的下限と排他的上限のデフォルト。包括的に編集します。ホテルのようなアプリケーションでは一般的であるため、通常はデフォルトを好みます。(私は2回目にホテルに入る、私は第八で下車、6日間滞在し、次のテナントが8日に来ることができます。)
ypercubeᵀᴹ

私は実際にどれにひっくり返されるかもしれません...今日範囲タイプについてちょうど見つけられて、私はドキュメントを読んでいます!
スパイク

何が望ましいか、2列か日付範囲付きの1列についてはわかりません。別の質問をすることができます。それはおそらくあなたが望む使い方、クエリ、使いやすさ(そしてインデックスのニーズ)に依存するでしょう。別々の列がある場合、たとえばにインデックスを付けると簡単です(product_id, start_date)。日付範囲では、それは上のインデックスでなければならない(product_id, lower(range_column))
ypercubeᵀᴹ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.