具有 NULL 值的复合唯一约束

Ima*_* Y. 3 postgresql constraint check-constraints unique-constraint

具有以下表结构

CREATE TABLE favorite_comments(
   id SERIAL PRIMARY KEY NOT NULL,
   opinion_id BIGINT REFERENCES opinions(id),
   review_id BIGINT REFERENCES reviews(id),
   list_id INTEGER REFERENCES lists(id) NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

这是有效记录(与同一列表相关的评论和意见):

id,  opinion_id,  review_id,  list_id
-------------------------------------
1,          333,       NULL,        4
2,         NULL,        444,        4
Run Code Online (Sandbox Code Playgroud)

但我想防止相同的评论或意见可能出现两次与同一个列表相关:

id,  opinion_id,  review_id,  list_id
-------------------------------------
1,          333,       NULL,        4
2,         NULL,        444,        4
3,         NULL,        444,        4 <- WRONG
Run Code Online (Sandbox Code Playgroud)

我想添加一个检查条件唯一性的约束UNIQUE(opinion_id, list_id) OR UNIQUE(review_id, list_id),但是因为opinion_id,review_id可以是 NULL 我对此有一些麻烦

我试过这个但不起作用

ALTER TABLE favorite_comments ADD CONSTRAINT comments_can_only_be_saved_once_per_list UNIQUE (opinion_id, review_id, list_id);

a_h*_*ame 5

如果您可以识别永远不会存储在引用表中的值(例如负值),您可以使用使用表达式的唯一索引:

create unique index 
  on favorite_comments( coalesce(opinion_id,-1), coalesce(review_id, -1), list_id );
Run Code Online (Sandbox Code Playgroud)

coalesce()会将所有空值转换为相同的“真实”值,从而在您尝试插入另一个 NULL 值时强制违反唯一约束。

与唯一约束相比,唯一索引的唯一缺点是,唯一索引不能作为外键的目标(而唯一约束是)