Postgresql:有条件的唯一约束

Eog*_*anM 87 postgresql constraints unique-constraint

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

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);
Run Code Online (Sandbox Code Playgroud)

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

这样做的任何方式?或者我应该回到关系绘图板?

Cra*_*ger 150

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

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);
Run Code Online (Sandbox Code Playgroud)

查看部分索引.

  • 超!不直观的是,"约束"没有显示为约束,但仍然给出了所谓的错误"错误:重复键值违反了唯一约束"stop_myc"` (20认同)
  • 显然,您_可以_在“ON CONFLICT DO UPDATE”中使用部分唯一索引,您只需重新声明索引的签名即可。在您的示例中,它将是“ON CONFLICT (col_a) WHERE (col_b is NOT null) DO UPDATE”。我使用的是版本 12;不确定什么时候添加的。 (12认同)
  • 值得注意的是,这种指数效应不能推迟.如果您需要执行批量更新,则可能会出现问题,因为在每一行之后检查唯一性,而不是像语句之后那样检查约束,或者在事务之后检查它是否为可延迟约束. (8认同)
  • 值得注意的是,这不会允许创建FK参考部分唯一字段. (6认同)
  • 请注意,您不能在“ON CONFLICT”表达式中使用它,因为它需要对表进行实际约束,而不仅仅是索引。 (5认同)

Pet*_*nko 24

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

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

有一种方法可以使用排除约束来实现它(感谢@dukelion这个解决方案)

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

ALTER TABLE stop
    ADD CONSTRAINT stop_col_a_key_part EXCLUDE (col_a WITH =) WHERE (col_b IS null);
Run Code Online (Sandbox Code Playgroud)

  • 虽然速度较慢,但​​排除解决方案的优势在于它是可延迟的(默认情况下会推迟到语句结束时).相反,不能延迟接受的唯一索引解决方案(并在每次更改行后检查).因此,通常无法进行批量更新,因为更新期间的步骤将违反唯一约束,即使在原子更新语句结束时不会违反该约束. (6认同)
  • 此注释已从 [2015 年 8 月](https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=049a7799dfce096923da27a9b0e4a3c7a0a47104) 的文档中删除 (5认同)