at.*_*at. 31 postgresql activerecord ruby-on-rails ruby-on-rails-4 rails-activerecord
我想在列上指定唯一索引,但我还需要允许NULL
值(多个记录可以包含NULL
值).使用PostgreSQL进行测试时,我发现我可以拥有一条带有NULL
值的记录,但下一个会导致问题:
irb(main):001:0> u=User.find(5)
User Load (111.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 5]]
=> #<User id: 5, email: "a@b.com", created_at: "2013-08-28 09:55:28", updated_at: "2013-08-28 09:55:28">
irb(main):002:0> u.email=nil
=> nil
irb(main):003:0> u.save
(1.1ms) BEGIN
User Exists (4.8ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" IS NULL AND "users"."id" != 5) LIMIT 1
(1.5ms) ROLLBACK
=> false
Run Code Online (Sandbox Code Playgroud)
因此,即使数据库允许,Rails也会首先检查是否User
存在具有不同id且email
列设置为NULL
.有没有一种方法,不仅数据库可以允许它,但Rails也不会像上面那样先检查?
这个想法是用户不必输入电子邮件,但如果他们这样做,我需要能够通过他们的电子邮件找到用户.我知道我可以创建另一个模型来将用户与电子邮件相关联,但我更愿意以上述方式进行操作.
更新:这是我为添加email
列而创建的迁移代码:
class AddEmailToUsers < ActiveRecord::Migration
def change
add_column :users, :email, :string
add_index :users, :email, :unique => true
end
end
Run Code Online (Sandbox Code Playgroud)
这是我添加到User
模型中的代码:
validates :email, uniqueness: true
Run Code Online (Sandbox Code Playgroud)
我忘了我已经将validates
调用添加到了User
模型中.所以Rails首先检查是有意义的.我想唯一的另一个问题是数据库是否可以安全地拥有唯一的索引和NULL
字段?有没有办法在Rails中指定我要验证的电子邮件是唯一的,除非它是nil
?
aro*_*oss 38
您的迁移将起作用并允许多个null
值(对于大多数数据库引擎).
但是您对用户类的验证应如下所示.
validates :email, uniqueness: true, allow_nil: true
Run Code Online (Sandbox Code Playgroud)
小智 16
为了澄清为什么这个工作在数据库级别,你必须了解在SQL中使用的三值逻辑:true
,false
,null
.
null
通常被认为是未知的,因此它在操作中的语义通常等同于不知道该特定值是什么,并且看你是否仍然可以得出答案.因此,举例来说1.0 * null
就是null
,但是null OR true
是true
.在第一种情况下,乘以未知是未知的,但在第二种情况下,条件的后半部分使整个语句始终为真,因此左侧的内容无关紧要.
现在谈到索引时,标准没有指定任何内容,因此供应商只能解释未知的含义.就个人而言,我认为应该在PostgreSQL文档中定义一个唯一索引:
当索引声明为唯一时,将不允许具有相等索引值的多个表行
那么问题应该是什么价值null = null
?应该是正确的答案null
.因此,如果您在那些PostgreSQL文档的行之间稍微阅读并说一个唯一索引将禁止多个行,对于该值,等于运算符返回true,null
则应允许多个值.这正是PostgreSQL的工作方式,因此在该设置中,您可以拥有一个包含多个行的唯一列null
作为值.
另一方面,如果您希望将唯一索引的定义解释为禁止不等式运算符不返回false的多个行,那么您将无法使多个行具有null
值.谁会选择在这种相反的设置中运作?这就是Microsoft SQL Server选择定义唯一索引的方式.
根据2003 SQL标准的定义,这两种定义唯一索引的方法都是正确的null
.所以它真的取决于你的底层数据库.但话虽如此,我认为大多数操作类似于PostgreSQL.
归档时间: |
|
查看次数: |
13316 次 |
最近记录: |