Rails where 条件使用 NOT NIL
Posted
技术标签:
【中文标题】Rails where 条件使用 NOT NIL【英文标题】:Rails where condition using NOT NIL 【发布时间】:2011-05-14 05:36:28 【问题描述】:使用 rails 3 风格我将如何写出相反的:
Foo.includes(:bar).where(:bars=>:id=>nil)
我想找到 id 不是 nil 的地方。我试过了:
Foo.includes(:bar).where(:bars=>:id=>!nil).to_sql
但是返回:
=> "SELECT \"foos\".* FROM \"foos\" WHERE (\"bars\".\"id\" = 1)"
这绝对不是我需要的,而且几乎看起来像是 ARel 中的一个错误。
【问题讨论】:
!nil
在 Ruby 中计算为 true
,而 ARel 在 SQL 查询中将 true
转换为 1
。因此,生成的查询实际上就是您所要求的 - 这不是 ARel 错误。
【参考方案1】:
使用 Rails 3 执行此操作的规范方法:
Foo.includes(:bar).where("bars.id IS NOT NULL")
ActiveRecord 4.0 及更高版本添加了where.not
,因此您可以这样做:
Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: id: nil )
在表之间使用范围时,我更喜欢利用merge
,以便更轻松地使用现有范围。
Foo.includes(:bar).merge(Bar.where.not(id: nil))
另外,由于includes
并不总是选择连接策略,所以这里也应该使用references
,否则可能会得到无效的SQL。
Foo.includes(:bar)
.references(:bar)
.merge(Bar.where.not(id: nil))
【讨论】:
最后一个不适合我,我们需要额外的 gem 或插件吗?我得到:rails undefined method 'not_eq' for :confirmed_at:Symbol
..
@Tim 是的,我在上面链接的 MetaWhere gem。
我喜欢不需要其他宝石的解决方案 :) 即使它有点难看
@oreoshake MetaWhere/Squeel 非常值得拥有,这只是一个小方面。当然,一般情况下最好知道。
@BKSpureon 链接 where
条件只是构建一个 AST,它不会访问数据库,直到您点击像 each
或 to_a
这样的终端方法。构建查询不是性能问题;你从数据库中请求的是什么。【参考方案2】:
这不是 ARel 中的错误,而是您的逻辑中的错误。
你想要的是:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
【讨论】:
我很好奇将 !nil 变成 '1' 的逻辑是什么 猜测,!nil 返回true
,这是一个布尔值。 :id => true
在 SQLese 中为您提供 id = 1
。
这是避免编写原始 sql 片段的好方法。虽然语法不如 Squeel 简洁。
我没有设法用 sqlite3 做到这一点。 sqlite3 想看field_name != 'NULL'
。
@zetetic 除非你使用的是 postgres,否则你会得到 id = 't'
:)【参考方案3】:
对于 Rails4:
所以,你想要的是一个内部连接,所以你真的应该只使用连接谓词:
Foo.joins(:bar)
Select * from Foo Inner Join Bars ...
但是,为了记录,如果你想要一个“NOT NULL”条件,只需使用 not 谓词:
Foo.includes(:bar).where.not(bars: id: nil)
Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL
注意,这个语法报告了一个弃用(它讲的是一个字符串 SQL sn-p,但我猜散列条件在解析器中被更改为字符串?),所以一定要在末尾添加引用:
Foo.includes(:bar).where.not(bars: id: nil).references(:bar)
弃用警告:您似乎急于加载表(一个 of: ....) 在字符串 SQL sn-p 中引用。例如:
Post.includes(:comments).where("comments.title = 'foo'")
目前,Active Record 识别字符串中的表,并且知道 将 cmets 表加入查询,而不是加载 cmets 在单独的查询中。然而,这样做没有写一个成熟的 SQL 解析器天生就有缺陷。因为我们不想写 SQL 解析器,我们正在删除此功能。从现在开始,你必须 当您从 字符串:
Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
【讨论】:
references
电话帮助了我!【参考方案4】:
不确定这是否有用,但这在 Rails 4 中对我有用
Foo.where.not(bar: nil)
【讨论】:
这是最好的答案。 -- 2017 robots.thoughtbot.com/activerecords-wherenot【参考方案5】:使用 Rails 4 很容易:
Foo.includes(:bar).where.not(bars: id: nil)
另请参阅: http://guides.rubyonrails.org/active_record_querying.html#not-conditions
【讨论】:
以上是关于Rails where 条件使用 NOT NIL的主要内容,如果未能解决你的问题,请参考以下文章