ChatGPT解决这个技术问题 Extra ChatGPT

Rails where 条件使用 NOT NIL

使用 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 错误。

n
notapatch

导轨 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")

最后一个对我不起作用,我们需要额外的 gem 或插件吗?我得到:rails undefined method 'not_eq' for :confirmed_at:Symbol..
@Tim 是的,我在上面链接的 MetaWhere gem。
我喜欢不需要其他宝石的解决方案:)即使它有点难看
@oreoshake MetaWhere/Squeel 非常值得拥有,这只是一个小方面。但当然,一般情况下很高兴知道。
@BKSpureon 链接 where 条件只是构建一个 AST,它不会访问数据库,直到您点击 eachto_a 之类的终端方法。构建查询不是性能问题;您从数据库中请求的是。
R
Ryan Bigg

这不是 ARel 中的错误,而是您的逻辑中的错误。

你在这里想要的是:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))

我很好奇将 !nil 变为 '1' 的逻辑是什么
猜测一下,!nil 返回 true,它是一个布尔值。 :id => true 让您id = 1 了解 SQLese。
这是避免编写原始 sql 片段的好方法。虽然语法不如 Squeel 简洁。
我还没有设法用 sqlite3 做到这一点。 sqlite3 想查看 field_name != 'NULL'
@zetetic 除非您使用的是 postgres,否则您会得到 id = 't' :)
R
Raed Tulefat

不确定这是否有用,但这在 Rails 4 中对我有用

Foo.where.not(bar: nil)

这是这里最好的答案。 -- 2017 robots.thoughtbot.com/activerecords-wherenot
M
Matt Rogish

对于 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 电话帮助了我!
T
Tilo

使用 Rails 4 很容易:

 Foo.includes(:bar).where.not(bars: {id: nil})

另请参阅:http://guides.rubyonrails.org/active_record_querying.html#not-conditions