如何为postgres添加部分约束并且与重叠的daterange一起使用?

问题描述

我正在使用--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-20-8909d368129a> in <module>() 12 13 m=1 ---> 14 if u>v: 15 m=m+1 16 else: NameError: name 'u' is not defined 表中名为valid_period的带有日期范围字段的postgres。

我用来添加约束的查询

thing_thing

这很好。

  • 具有相同 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; 且重叠team_id =>的行被阻止?
  • 具有不同的valid_period和重叠的team_id =>的行✅
  • 具有相同valid_period并且不重叠team_id =>的行row

我需要什么但不确定如何做

但是我只希望约束在IF中发挥作用

  • 字段valid_period(布尔字段)也是false或
  • 字段is_removed(varchar字段)包含任何可能的值之一,例如stateCANCELLED

因此以下操作无效:

  • 具有相同的REJECTED和重叠的team_id但行valid_period为True的行=>预期允许✅但被​​阻止?
  • 具有相同的is_removed和重叠的team_id但行valid_periodstate的行=>预期允许✅但被​​阻止?
  • 具有相同的CANCELLED和重叠的team_id但行valid_periodstate的行=>预期允许✅但被​​阻止?

如何更改约束以允许例外?换句话说,有点像局部唯一索引。

我有点悲观,因为我了解不存在来自另一个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,'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,2021-01-01)).

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