PostgreSQL唯一索引复合键

PostgreSQL唯一索引复合键,sql,postgresql,null,indexing,unique-index,Sql,Postgresql,Null,Indexing,Unique Index,我需要基于四列对一个表创建一个限制,其中两列是互斥的,我的意思是,如果一列为NULL,另一列则不是 理想的脚本是: ALTER TABLE ONLY t_users_prizes ADD CONSTRAINT t_user_prize_test_circuit_key UNIQUE (id_event||':'||id_circuit, id_prize, id_user); 但是Postgres不允许这种连接 如何实现此限制?强制a、b中的一个必须为空 但空值不会违反唯一约束-两个空值永远不

我需要基于四列对一个表创建一个限制,其中两列是互斥的,我的意思是,如果一列为NULL,另一列则不是

理想的脚本是:

ALTER TABLE ONLY t_users_prizes
ADD CONSTRAINT t_user_prize_test_circuit_key
UNIQUE (id_event||':'||id_circuit, id_prize, id_user);
但是Postgres不允许这种连接

如何实现此限制?

强制a、b中的一个必须为空

但空值不会违反唯一约束-两个空值永远不会被视为相等!因此,简单的唯一约束不起作用

您可以使用两个唯一的索引完成此操作:

我声明c和d不为空,以防止进一步的复杂化

如果您还想禁止1,NULL,3,4和NULL,1,3,4请参见我的评论,您可以使用一个带有COALESCE的索引:

强制a、b中只有一个必须为NULL

但空值不会违反唯一约束-两个空值永远不会被视为相等!因此,简单的唯一约束不起作用

您可以使用两个唯一的索引完成此操作:

我声明c和d不为空,以防止进一步的复杂化

如果您还想禁止1,NULL,3,4和NULL,1,3,4请参见我的评论,您可以使用一个带有COALESCE的索引:


您是否允许1,NULL,3,4和NULL,1,3,4共存?据我所知,与@Erwin和Catcall answers中暗示的相反,这两个互斥列都不能为NULL。正确的解释是什么?我们的两个答案都不允许一对空值。您是否允许1,NULL,3,4和NULL,1,3,4共存?据我所知,与@Erwin和Catcall答案中暗示的相反,两个互斥列都不能为空。正确的解释是什么?我们的两个答案都不允许一对空。回答得很好!这就解决了问题,鼓励我在博士后做新的事情。谢谢下一个任务:分区表!很好的回答!这就解决了问题,鼓励我在博士后做新的事情。谢谢下一个任务:分区表!
CREATE TEMP TABLE foo (
   a int
  ,b int
  ,c int NOT NULL
  ,d int NOT NULL
  ,CHECK ((a IS NOT NULL AND b IS NULL) OR (b IS NOT NULL AND a IS NULL))
);

CREATE UNIQUE INDEX foo_acd_idx ON foo(a,c,d)
WHERE b is NULL;

CREATE UNIQUE INDEX foo_bcd_idx ON foo(b,c,d)
WHERE a is NULL;

INSERT INTO foo VALUES (NULL,2,3,4);
INSERT INTO foo VALUES (NULL,2,3,4);  -- error! 
CREATE UNIQUE INDEX foo_xcd_idx ON foo(COALESCE(a,b),c,d);