对特定配对的唯一约束

Gav*_*nis 0 postgresql database-design unique-constraint

我试图找出一个特殊的UNIQUE约束:表中有很多列Users,但只有这两列与问题相关:

id bigint,
active boolean,
...
Run Code Online (Sandbox Code Playgroud)

我想允许多行具有相同的id-其中只有一行可能具有active = true.

例如,可以有很多行包含id = 1active = false,但只有一行可以包含id = 1active = true

Vér*_*ace 5

为此,您可以利用一个非常有用的 PostgreSQL 功能 - partial index.

你有你的桌子:

CREATE TABLE foo
(
  id BIGINT NOT NULL,
  --
  -- other fields
  --
  active BOOLEAN NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

然后,你这样做:

CREATE UNIQUE INDEX ON foo (id) 
WHERE active;  -- if you prefer more clarity, could have "WHERE active = TRUE;"
Run Code Online (Sandbox Code Playgroud)

所以,我们尝试一下(请参阅此处的小提琴):

--
-- `active` - all false for a given id - works
--
INSERT INTO foo 
VALUES (1, FALSE), (1, FALSE), (1, FALSE); 
Run Code Online (Sandbox Code Playgroud)

查看:

SELECT * FROM foo;
Run Code Online (Sandbox Code Playgroud)

结果:

id  active
1   f
1   f
1   f
Run Code Online (Sandbox Code Playgroud)

另一种可能性 - 与问题相关的具体可能性:

--
-- one and only one `active` = true for a given id - works
--
INSERT INTO foo 
VALUES (2, FALSE), (2, FALSE), (2, TRUE);
Run Code Online (Sandbox Code Playgroud)

查看:

SELECT * FROM foo;
Run Code Online (Sandbox Code Playgroud)

结果:

id  active
1   f
1   f
1   f
2   f
2   f
2   t
Run Code Online (Sandbox Code Playgroud)

最后一个考试:

--
--  attempt to INSERT two true `active` values for a given id - fails!
--
INSERT INTO foo
VALUES (3, FALSE), (3, FALSE), (3, TRUE), (3, TRUE);
Run Code Online (Sandbox Code Playgroud)

结果:

ERROR:  duplicate key value violates unique constraint "foo_id_idx"
DETAIL:  Key (id)=(3) already exists.
Run Code Online (Sandbox Code Playgroud)

foo不变,这就是我们想要的!