使用 rails 3 样式我将如何编写相反的内容:
Foo.includes(:bar).where(:bars=>{:id=>nil})
我想找到 id 不为零的地方。我试过了:
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 错误。
导轨 4+
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))
导轨 3
使用 Rails 3 执行此操作的规范方法:
Foo.includes(:bar).where("bars.id IS NOT NULL")
这不是 ARel 中的错误,而是您的逻辑中的错误。
你在这里想要的是:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
true
,它是一个布尔值。 :id => true
让您id = 1
了解 SQLese。
field_name != 'NULL'
。
id = 't'
:)
不确定这是否有用,但这在 Rails 4 中对我有用
Foo.where.not(bar: nil)
对于 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 片段,但我猜散列条件在解析器中更改为字符串?),因此请务必将引用添加到末尾:
Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)
弃用警告:看起来您正在急切加载在字符串 SQL 片段中引用的表(以下之一:...)。例如: Post.includes(:comments).where("comments.title = 'foo'") 目前,Active Record 识别字符串中的表,并知道将评论表加入到查询中,而不是将评论加载到一个单独的查询。然而,在不编写成熟的 SQL 解析器的情况下这样做是有内在缺陷的。由于我们不想编写 SQL 解析器,因此我们将删除此功能。从现在开始,当你从一个字符串中引用一个表时,你必须明确告诉 Active Record: Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
references
电话帮助了我!
使用 Rails 4 很容易:
Foo.includes(:bar).where.not(bars: {id: nil})
另请参阅:http://guides.rubyonrails.org/active_record_querying.html#not-conditions
rails undefined method 'not_eq' for :confirmed_at:Symbol
..where
条件只是构建一个 AST,它不会访问数据库,直到您点击each
或to_a
之类的终端方法。构建查询不是性能问题;您从数据库中请求的是。