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

时间:2014-02-07 20:56:23

标签: sql ruby-on-rails postgresql indexing unique-constraint

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

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

但是,我想允许用户将价格添加到未引用的line_items。只需一个价格即可正常工作,quote_id为空且line_item_id存在。但是,唯一索引阻止我将第二个价格附加到同一line_itemquote_id中的空值被视为唯一。

有没有办法让这个唯一约束仅在引用不为空时才适用? 我知道allow_nil可以用于模型验证,但它可以在索引中使用吗?

我想的是:

add_index :prices, [:quote_id, :line_item_id], :unique => true, :allow_nil => true

PostgreSQL和Rails 4。

1 个答案:

答案 0 :(得分:2)

  

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

实际上,这是 唯一的方式。您可以拥有多个“相同”条目,多列索引中的一个或多个列为NULL,因为Postgres不会为此目的考虑两个NULL值相同(如在大多数情况下)。 / p>

索引中的列序列对此无关紧要。 (It matters for other purposes, though.

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

重新阅读你的问题之后,更合适的情况似乎是这个相关的答案:
Create a multicolumn index to enforce uniqueness
这个也可能有所帮助,但问题是要求你的相反
How to add a conditional unique index on PostgreSQL

如果你实际上想要一个只有非空值的partial index,那么你也可以这样做:

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;

但是,为了您的目的,您并不需要 。从索引中排除具有NULL值的行可能仍然有用,以使其更快。详情:
Indexed ORDER BY with LIMIT 1