如何在多列的唯一索引中允许一列的 NULL 值

Fot*_*Man 5 sql postgresql indexing ruby-on-rails unique-constraint

似乎是一个非常简单的问题,但我似乎无法在网上的任何地方找到具体的答案。

我有一个price引用报价和行项目的模型,因此它有quote_idline_item_id列。我正在使用多列索引unique: true来防止同一 line_item 的多个价格附加到报价中。quote_id是索引中的第一列。

但是,我希望允许用户添加line_items尚未报价的价格。它适用于一个价格,quote_id为空且line_item_id存在。但是,唯一索引阻止我将第二个价格附加到相同的line_item. 中的空值quote_id被视为唯一的。

有什么方法可以使唯一约束仅在引用不为空时适用?
我知道allow_nil可以在模型验证中使用,但是可以在索引中使用吗?

我在想这样的事情:

add_index :prices, [:quote_id, :line_item_id], :unique => true, :allow_nil => true
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 和 Rails 4。

Erw*_*ter 3

有什么方法可以使唯一约束仅在引用不为空时适用吗?

事实上,这是唯一的办法。您可以拥有多个“相同”条目,其中多列索引中的一个或多个列为NULL,因为 Postgres 不会NULL为此目的考虑两个相同的值(就像在大多数情况下一样)。

索引中列的顺序对此并不重要。(不过,这对于其他目的很重要。

确保表本身中的基础列可以是NULL。(有时与空字符串混淆''。)

重新阅读您的问题后,更合适的场景似乎是以下相关答案:
创建多列索引以强制唯一性
这也可能有帮助,但问题要求与您相反:
如何添加条件唯一性PostgreSQL 上的索引

如果您实际上想要一个仅包含非空值的部分索引,您也可以这样做:

CREATE INDEX price_uni_idx ON price (quote_id, line_item_id)
WHERE  quote_id     IS NOT NULL
AND    line_item_id IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)

不过,您不需要它来实现您的目的。从索引中排除具有 NULL 值的行以提高索引速度可能仍然有用。详细信息请参见:
带 LIMIT 1 的索引 ORDER BY