PostgreSQL:条件唯一约束


116

我想添加一个约束,该约束仅在表的一部分中对列强制实施唯一性。

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

WHERE上面的部分是一厢情愿的想法。

有什么办法吗?还是我应该回到关系绘图板上?


2
经常做。请参阅“部分唯一索引”
Craig Ringer 2013年

11
@yvesonline不,这是一个常规的唯一约束。发布者想要部分唯一约束。
Craig Ringer

Answers:


186

PostgreSQL没有定义部分(即条件)UNIQUE约束-但是,您可以创建部分唯一索引。PostgreSQL使用唯一索引来实现唯一约束,因此效果是一样的,只是您不会看到中列出的约束information_schema

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

请参阅部分索引


24
超!直觉认为“约束”不会显示为约束,但是却给出了所需的错误ERROR: duplicate key value violates unique constraint "stop_myc"
EoghanM 2013年

7
值得注意的是,这将不允许创建FK引用该部分唯一字段。
ffflabs

11
还值得注意的是,该索引效果不能被推迟。如果您需要执行批量更新,则可能会出现问题,因为在每一行之后都要检查唯一性,而不是像在语句之后那样对约束进行检查,或者在事务之后像对延迟约束那样进行检查。
sage88

37

已经说过,PG没有定义部分(即有条件的)UNIQUE约束。还有文档说,向表添加唯一约束的首选方法是ADD CONSTRAINT 唯一索引

向表添加唯一约束的首选方法是ALTER TABLE ... ADD CONSTRAINT。使用索引强制实施唯一约束可以被认为是不应直接访问的实现细节。但是,应该知道,无需在唯一列上手动创建索引;这样做只会复制自动创建的索引。

有一种方法可以使用“ 排除约束”来实现(感谢@dukelion提供此解决方案)

在您的情况下,它看起来像

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

在这种方法上,您不使用“使用”来定义索引方法,因此这可能会非常慢,或者postgres在该方法上创建默认索引?该方法是规范的选择,但从来没有更好的选择!我认为您将需要一个带有索引的“ using”子句,以使该选择成为更好的选择。
Natan Medeiros,

10
尽管速度较慢,但​​exclude解决方案的优点是它可以延迟(默认情况下,延迟到语句结尾)。相反,不能推迟接受的唯一索引解决方案(并且在每次更改行后都会对其进行检查)。因此,批量更新通常是不可能的,因为更新过程中的步骤会违反唯一约束,即使在原子更新语句的末尾也不会违反唯一约束。
sage88

1
该笔记于2015
-Raniz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.