【问题标题】:Exclude 'nil' row from ActiveRecord query with a HAVING clause where no results are returned使用没有返回结果的 HAVING 子句从 ActiveRecord 查询中排除“nil”行
【发布时间】:2023-04-09 02:59:01
【问题描述】:

我正在模型中构建一系列方法以用作范围。当其中一个使用 having 子句并且该查询不返回任何结果时,我会得到一个返回的模型实例,其中所有字段都是 nil,这会破坏我想在其中使用这些范围的大多数代码。

下面是一个高度简化的示例来演示我的问题。

class Widget < ActiveRecord::Base
  attr_accessible :name

  has_many :components

  def without_components
    joins(:components).group('widgets.id')having('COUNT(components.id) = 0')
  end

  def without_components_and_remove_nil
    without_components.select{|i| i.id} # Return objects where i.id is not nil
  end
end

如果所有 Widget 都分配了组件,则调用 Widget.without_components 会返回非期望值:

[{id: nil, name: nil, user_id: nil}]

但是,如果我调用 Widget.without_components_and_remove_nil,它会将要返回的 ActiveRecord::Relation 对象转换为 Array,因此我无法将它与其他范围链接,因为我需要这样做。

有没有办法更改范围,以便在出现 nil 行时将其排除,或者是否可以对我的 ActiveRecord 查询进行修改以使其正常工作?

【问题讨论】:

  • 您到底是如何设法将没有 id 的记录放入数据库的?
  • 不是没有ID的记录,是SQL生成的结果。我正在使用 MySQL,不知道这是否有区别,但是当有一个 HAVING 子句不返回任何结果时,它是 MySQL 返回所有 nil 的行;它实际上不在表格中。

标签: ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

我需要解决两个问题才能使该范围正常工作;一个与我最初的问题无关,尽管没有它我上面介绍的范围就不会得到解决:

  • 首先,直接处理手头的问题,从 Rails 3.1 开始,您可以这样做:

.

Widget.where(id: Widget.joins(:components).group('widgets.id').having('COUNT(components.id)'))
  • 其次,它的joins(:components) 部分不能与having('COUNT(components.id = 0)') 一起使用,因为joins 执行内部连接,因此该查询永远不会有任何结果。我不得不将joins 替换为joins("LEFT OUTER JOIN components ON components.widget_id = widgets.id")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多