如何添加部分约束并且还适用于 postgres 的重叠日期范围?

How to add a constraint that's partial and also works with overlapping daterange for postgres?

我在 thing_thing table.

中使用带有名为 valid_period 的日期范围字段的 postgres

我用来添加约束的查询


CREATE EXTENSION IF NOT EXISTS btree_gist;

ALTER TABLE thing_thing 
ADD CONSTRAINT prevent_overlapping_valid_periods_by_team 
        EXCLUDE USING gist(team_id WITH =, valid_period WITH &&) 
        DEFERRABLE INITIALLY DEFERRED;

这个效果很好。

我需要什么但不知道该怎么做

但我只希望约束在 IF

中生效

因此以下内容不起作用:

如何更改约束以允许例外?也就是说,有点像partial unique index.

我有点悲观,因为我知道没有来自另一个 SO 答案的部分约束 here

但同时,我认为不可能使用部分唯一索引来防止非法重叠日期范围。

您可以为此使用部分索引 - 至少您可以使用 PostgreSQL v13 - 尚未检查其他索引。

请注意 WHERE 条件中的括号 - 如果您忘记这些括号,它会提出抗议。

下面的示例根据您的描述进行了稍微简化,但逻辑上是相同的。

=> CREATE TABLE teams (team_id int not null, valid_period daterange not null, is_removed boolean not null, state char not null);

=> ALTER TABLE teams ADD CONSTRAINT no_overlaps 
    EXCLUDE USING gist(team_id WITH =, valid_period WITH &&)
    WHERE (is_removed = false OR state IN ('C','R'));

=> INSERT INTO teams VALUES (1, daterange('2020-01-01', '2021-01-01'), false, 'X');
INSERT 0 1

=> INSERT INTO teams VALUES (1, daterange('2020-01-01', '2021-01-01'), false, 'X');
ERROR:  conflicting key value violates exclusion constraint "no_overlaps"
DETAIL:  Key (team_id, valid_period)=(1, [2020-01-01,2021-01-01)) conflicts with existing key (team_id, valid_period)=(1, [2020-01-01,2021-01-01)).

=> INSERT INTO teams VALUES (1, daterange('2020-01-01', '2021-01-01'), true, 'X');
INSERT 0 1

=> INSERT INTO teams VALUES (1, daterange('2020-01-01', '2021-01-01'), true, 'C');
ERROR:  conflicting key value violates exclusion constraint "no_overlaps"
DETAIL:  Key (team_id, valid_period)=(1, [2020-01-01,2021-01-01)) conflicts with existing key (team_id, valid_period)=(1, [2020-01-01,2021-01-01)).