【问题标题】:Exclude object if one of the has_many related entities has the attribute with value x如果 has_many 相关实体之一具有值为 x 的属性,则排除对象
【发布时间】:2014-10-16 10:24:26
【问题描述】:

我遇到了排除数据的问题,如果关联数据之一的属性 x 具有值“a”。

例子:

class Order < ActiveRecord::Base
  has_many :items
end

class Item < ActiveRecord::Base
  belongs_to :order

  validate_presence_of :status
end

查询应返回所有具有status = 'paid'(status !='paid')的商品的订单。

由于 1:n 关联,一个订单可以有多个项目。并且其中一个 Itmes 可以具有 status = 'paid'。这些订单必须从我的查询结果中排除,即使订单有其他状态不同于“已付款”的商品。

我将如何解决这个问题:

paid_items = Items.where(status: 'paid').pluck(:order_id)
orders_wo_paid = Order.where('id NOT IN (?)', paid_items)

是否有 ActiveRecord 解决方案,可以在一个查询中解决此问题。 或者有其他方法可以解决这个问题吗?

我不是在寻找红宝石解决方案,例如:

Order.select do |order|
  !order.items.pluck(:status).include?('paid')
        
end

感谢您的想法和灵感。

【问题讨论】:

  • 您可以使用嵌套的 sql 查询来解决它,但我认为它不会比您自己的解决方案更有效率,而且它的可读性肯定会降低。我个人会选择你所拥有的。
  • 或者使用左连接 + 分组 + 计数,但是左连接在 ActiveRecord 中使用并不那么简单,而且它也更难阅读。顺便说一句,我认为这是一个错字,但你从Items 中提取的应该是order_id 而不是id
  • 确定 order_id,谢谢..
  • @Fer:能不能举个左连接+分组+计数的例子!

标签: ruby-on-rails ruby activerecord


【解决方案1】:

你可以这样做:

Order.where('orders.id NOT IN (?)', Item.where(status: 'paid').select(:order_id))

如果您使用的是 Rails 4.x,那么:

Order.where.not(id: Item.where(status: 'paid').select(:order_id))

【讨论】:

  • UUps... 它不起作用。具有 items.status 'paid' 和其他状态为 != 'paid' 的订单将出现在结果中。谢谢
  • @nabinabou:啊哈,我明白你想说什么了。请查看更新。
  • 现在,您的查询是正确的,与问题相关。但是这个解决方案与问题中提到的相同。这不是解决它的新方法。仍在使用两个查询。
【解决方案2】:

您感兴趣的查询如下,但使用 activerecord 创建将很难/不太可读:

SELECT 
  orders.*
FROM 
  orders
LEFT JOIN 
  order_items ON orders.id = order_items.order_id
GROUP BY
  order_items.order_id
HAVING 
  COUNT(DISTINCT order_items.id) = COUNT(DISTINCT order_items.status <> 'paid')

对不起,sql缩进,我不知道它的约定是什么。

使用 rails 的一种方法(根本不是最好的方法)(不幸的是,为最重要的部分编写 sql)如下:

Order.group(:order_id).joins("LEFT JOIN order_items ON orders.id = order_items.order_id")
     .having("COUNT(DISTINCT order_items.id) = COUNT(DISTINCT order_items.status <> 'paid')")

当然你可以玩 AREL 来摆脱硬编码的 sql,但我认为它不会更容易阅读。

您可以在此要点中找到创建左连接的示例:https://gist.github.com/mildmojo/3724189

【讨论】:

  • 要更正查询,它应该是 items.status != 'paid'。所以你会得到没有任何付费项目的订单。
猜你喜欢
  • 2021-07-19
  • 1970-01-01
  • 2023-04-06
  • 2017-07-24
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
相关资源
最近更新 更多