更改表列以添加约束,其中列不为空

时间:2011-07-22 04:41:15

标签: sql postgresql

我有这个:

alter table supplier
add constraint supplier_unique
unique (supplier_id) where supplier_id is not null;

但我收到了错误。

结果定义应为:

CREATE UNIQUE INDEX supplier_unique
ON supplier (supplier_id) WHERE (supplier_id IS NOT NULL)

感谢。

1 个答案:

答案 0 :(得分:4)

PostgreSQL中的unique constraint没有WHERE子句,因此您在“where”处收到语法错误。在任何情况下,supplier_id is not null都不需要具有唯一约束:

  

通常,如果表中有多行,其中约束中包含的所有列的值相等,则会违反唯一约束。但是,在此比较中,两个空值不相等。这意味着即使存在唯一约束,也可以在至少一个约束列中存储包含空值的重复行。此行为符合SQL标准,...

所以你需要的就是:

alter table supplier
add constraint supplier_unique
unique (supplier_id);

您的唯一约束将被添加,您可以拥有多个supplier_id IS NULL行,并且您将索引作为唯一约束的副作用。

但是,如果要直接创建索引,可以create a partial index使用谓词:

  

当存在WHERE子句时,将创建部分索引。部分索引是一个索引,它只包含表的一部分的条目,通常是比索引的其余部分更有用的索引部分。
  [...]
  另一个可能的应用是使用带有UNIQUE的WHERE来强制表的一个子集的唯一性。

但是在NULL的情况下,supplier_id IS NOT NULL的部分索引不会对唯一性做任何事情,因为PostgreSQL唯一约束已经允许多个NULL值(可能是因为标准因为x = NULL是所有x)都是假的。

因此,如果您的意图过于限制非NULL值的唯一性,那么您不需要您的部分索引;但是,如果您只是想避免索引NULL值,那么您可以通过CREATE INDEX(但不是ALTER TABLE)来完成。我不知道是否从你的索引中留下NULL会产生任何明显的影响。

我认为部分混乱(你和我的)是UNIQUE既是约束又是索引。您可以在将其创建为索引时包括WHERE,但在将其创建为约束时则不包括WHERE。这肯定是不一致的。