【问题标题】:Rails + PostgreSQL: How to get products that have been ordered at least once + get the order # and the manager idRails + PostgreSQL:如何获取至少订购一次的产品+获取订单#和经理ID
【发布时间】:2019-12-05 21:04:20
【问题描述】:

我有这些模型:

class Product < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
 belongs_to :product
end

我想获取至少订购过一次的所有产品的列表,以及下单时间的时间戳 (orders.created_at) 和订单代码 (orders.no) 以及管理员处理了订单(orders.processed_by_admin_id)。最后,我想通过orders.created_at 列出输出。

经过一番谷歌搜索,我想出了这样的东西:

Product.joins(:orders)
       .group("(products.id) having count(products.id) > 0")
       .select("products.*", "max(orders.created_at) as last_order_time")
       .sort_by(&:last_order_time).reverse

这让我得到了至少一次订购的产品列表,按时间戳排序。但是,我被困在这里无法获取orders.noorders.processed_by_admin_id。我不确定我遵循的程序是否正确。

所需的输出类似于:

products.* | last_order_time | order_no | order_processed_by_admin_id

任何建议表示赞赏。

【问题讨论】:

  • 我尝试了很多次以获得类似的效果,但总是失败。它表明通过 ActiveRecord 对模型 Product 进行 SQL 查询,您只能在该模型的模式定义的结果字段中获得。因为我在需要时从不需要生产中的这些数据,所以我只是添加as 来查询以欺骗 ActiveRecord。所以前。 .select("products.id", "max(orders.created_at) as products.field_you dont_need", "orders.no", "orders.processed_by_admin_id") 我希望你可以通过一些attr_reader 来实现它,但不幸的是没有。所以不仅仅是帮助我还在等待答案
  • 当然你可以通过像Product.connection.select_all('sql')这样的原始查询得到它,但它不会给出对象,只是简单的记录

标签: ruby-on-rails ruby postgresql activerecord


【解决方案1】:

我想获取至少订购一次的所有产品的列表,以及下单时间的时间戳 (orders.created_at) 和订单代码 (orders.no) 以及管理员处理订单(orders.processed_by_admin_id)。最后,我想按 orders.created_at 列出输出。

在编写复杂的查询时,我喜欢先编写简单的 SQL。

让我们从查询获取每个产品的最新订单开始。

select product_id, id, 
  row_number() over ( 
    partition by product_id order by created_at 
  ) as recency_ranking 
from orders
;

这称为window function。对于每个产品,最新订单的 recency_ranking 为 1。现在我们可以将此查询加入到我们的 products 表中。

select p.*,
  x.id as order_id,
  x.no as order_number,
  x.order_processed_by_admin_id,
  x.created_at as order_created_at
from products p
inner join (
  select product_id, 
    id, 
    created_at, 
    row_number() over ( 
      partition by product_id order by created_at 
    ) as recency_ranking,
    no,
    order_processed_by_admin_id 
  from orders
) x
  on x.product_id = p.id
    and x.recency_ranking = 1
order by x.created_at
;

当我们像这样加入另一个查询时,它称为子查询。注意我们如何加入on recency_ranking = 1

要在 ActiveRecord 中运行整个查询,我建议find_by_sql

products = Product.find_by_sql('select p.*, x.id ...')
products.first.order_created_at #=> '2019-01-01 ...'

【讨论】:

  • 谢谢@JaredBeck,答案很好,确实解决了我的问题!只是想知道order_processed_by_admin_id - 在Order 模型中,它具有属于Admin 模型的关联。但是,当我尝试这样的事情时:products.first.order_processed_by_admin.full_name,我收到此错误消息:undefined method 'admin' for #&lt;Product:0x007fb1aa1381f8&gt;。关联好像坏了?
  • Re: "未定义方法 'admin' for Product",是 Order 有这个关联,不是 Product,对吧?因此,错误消息是正确且预期的。而是使用product.order.admin(效率低下)或将admins 表加入到大查询中。
  • 只是想知道 - 我如何还包括 products 的总数?我试过这样:select p.*, x.id as order_id, x.no as order_number, x.order_processed_by_admin_id, x.created_at as order_created_at, COUNT(x.id) as total_orders ...,但它总是给我1。计划 B 将在 Rails 中获取计数,但将其放在查询中会更有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 2011-08-03
  • 2017-09-25
  • 1970-01-01
  • 2021-12-06
  • 2018-11-21
相关资源
最近更新 更多