【问题标题】:Postgres unique contraint ignores null values but Rails passesPostgres 唯一约束忽略空值但 Rails 通过
【发布时间】:2018-06-12 18:15:50
【问题描述】:

我在我的 postgres 数据库中有一个唯一索引,在这样的表 participations

"participation_uniqueness" UNIQUE, btree (event_id, firstname, lastname, email)

这很好,除了如果其中一个字段为 nil,它基本上会被忽略:

event_id |名字 |姓氏 |电子邮件
1982 |约翰 |能源部 | john@doe.de
1982 |汉斯 |能源部 | john@doe.de
1982 |空 |空 | john@doe.de
1982 |空 |空 | john@doe.de

如果值为空,我希望唯一性约束也适用,因此上面示例表中的最后一条记录不应该是可能的,因为它违反了唯一性约束。

在 Rails 中,我可以简单地将其作为验证方法添加到我的模型中

validates_uniqueness_of :email, scope: [:event_id, :firstname, :lastname]

我想知道为什么这个验证会考虑 NULL 进行唯一性检查,而 SQL 却没有?

研究这个主题我知道它是 SQL 标准,因为NULL 被解释为“缺失信息”,您无法相互比较缺失的信息。

但是从逻辑的角度来看,这对我来说毫无意义。在这种情况下,我希望数据库插入失败。例如,我如何在不实施此处发布的肮脏变通办法的情况下实现这一目标 https://www.pgrs.net/2008/01/11/postgresql-allows-duplicate-nulls-in-unique-columns/

【问题讨论】:

  • However from a logical point of view this makes no sense to me 为什么只允许一个人无名?一个人应该被允许存在而没有名字吗?如果答案是“是”,那么 每个 人都应该是“是”! (ergo:您的数据定义/模型与现实不符)

标签: ruby-on-rails postgresql


【解决方案1】:

有一个使用部分索引的潜在答案here

CREATE UNIQUE INDEX ab_c_null_idx ON my_table (a, b) WHERE c IS NULL;

Rails 的行为不同,因为它在 uniqueness validator 中做了更多的事情。它不仅仅是运行查询。

【讨论】:

  • 是的,这很糟糕@DonMB - 可能值得在 irc 上的 postgres 频道上跳转。我希望有更好的解决方案,但我看不到。您还必须考虑查询等,并确保您实际点击索引。
猜你喜欢
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 2012-01-28
相关资源
最近更新 更多