Postgresql:条件唯一约束

Posted

技术标签:

【中文标题】Postgresql:条件唯一约束【英文标题】:Postgresql: Conditionally unique constraint 【发布时间】:2013-04-20 14:57:49 【问题描述】:

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

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

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

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

【问题讨论】:

常用。请参阅“部分唯一索引” @yvesonline 不,这是一个常规的唯一约束。张贴者想要一个部分唯一约束。 【参考方案1】:

PostgreSQL 没有定义部分(即条件)UNIQUE 约束 - 但是,您可以创建部分唯一的索引

PostgreSQL 使用唯一索引来实现唯一约束,因此效果是相同的,但有一个重要警告:您不能像对唯一约束一样对唯一索引执行 upserts (ON CONFLICT DO UPDATE)。

此外,您不会看到information_schema 中列出的约束。

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

见partial indexes。

【讨论】:

超级!不直观的是,“约束”没有显示为约束,但仍然给出了所需的错误 ERROR: duplicate key value violates unique constraint "stop_myc" 值得注意的是,这将不允许创建引用该部分唯一字段的 FK。 另外值得注意的是,这个索引效果不能被推迟。如果您需要执行批量更新,这可能会出现问题,因为在每一行之后检查唯一性,而不是在语句之​​后检查约束,或者在事务之后检查延迟约束。 请注意,您不能在ON CONFLICT 表达式中使用它,因为它需要对表进行实际约束,而不仅仅是索引。 通过注释在 php 的 Doctrine ORM 框架中实现这一点如下所示:@Table(name="ecommerce_products",uniqueConstraints=@UniqueConstraint(name="stop_myc", columns="col_a", "col_b", options="where": "(col_b IS NOT NULL)")) 根据文档:doctrine-project.org/projects/doctrine-orm/en/2.8/reference/…【参考方案2】:

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

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

有一种方法可以使用Exclusion Constraints 来实现它,(感谢@dukelion 提供此解决方案)

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

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

【讨论】:

在那种方法上你不使用“使用”来定义索引方法,所以这可能非常慢或者postgres创建一个默认索引?该方法是规范的选择,但不是更好的选择!我认为您需要一个带有索引的“使用”子句才能使该选择成为更好的选择。 虽然速度较慢,但​​排除解决方案的优点是它是可延迟的(默认情况下会延迟到语句结束)。相反,接受的唯一索引解决方案不能被推迟(并且在每次行更改后检查)。所以批量更新通常是不可能的,因为更新过程中的步骤会违反唯一性约束,即使它不会在原子更新语句的末尾被违反。 此注释已从 august 2015 中的文档中删除

以上是关于Postgresql:条件唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

postgresql字段值唯一约束

如何在 postgresql 中对 json 类型使用唯一约束

PostgreSQL:基于多列唯一约束的自增

postgresql----数据库表约束----UNIQUE

Postgresql多个表具有相同的外键唯一约束

postgresql 重复键违反唯一约束