日期范围的唯一性约束


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

我希望数据库执行以下规则,即在日期范围内(通过where <date> BETWEEN start_date AND end_date)某种产品在特定数量上只能有一个价格。

这种基于范围的约束可行吗?

Answers:


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,相同quantity和重叠(&&)日期范围。

'[]'是为希望全包的日期范围(默认是[)用于范围类型)。

请参阅有关范围类型约束的文档。您可能还需要通过运行添加扩展名(一次,对于要安装此扩展名的每个数据库):

CREATE EXTENSION btree_gist;

这太棒了。我不认为这daterange完全相同的,因为它是排他的下限,但这很容易解决。我是否应该真正地将数据迁移为使用daterange列类型(如果更好,可以单独提出一个问题),或者这两个列的内容是否合理?
峰值

如果我记得很好的话,默认的包含下限和排除上限。我将进行全包编辑。我通常喜欢默认设置,因为它在类似酒店的应用程序中很常见。(我得到在酒店的2,我在8号下车,逗留6天后接下来的占用可以进来在第8位。)
ypercubeᵀᴹ

实际上,我可能会迷上哪个是哪个...今天才发现有关范围类型,我正在阅读文档!
峰值

我不知道最好是2列还是带daterange的列。您可以提出一个单独的问题。它可能取决于您想要的用法,查询,易用性(以及索引需求)。如果有单独的列,例如在上创建索引会更容易(product_id, start_date)。随着日期范围,将必须要对一个指标(product_id, lower(range_column))
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.