Rails ActiveRecord在一个查询中执行Group,Sum和Count

And*_*phy 12 ruby ruby-on-rails rails-activerecord

我有两张桌子,

Order (ID, Value)
Run Code Online (Sandbox Code Playgroud)

OrderType (ID, Name [Quote, Sale, Purchase, etc])
Run Code Online (Sandbox Code Playgroud)

我想获得每种类型(计数)的订单总数以及每种类型的订单总数(总和)

我可以单独使用这些

Order.group(:order_type).count(:id)
Run Code Online (Sandbox Code Playgroud)

Order.group(:order_type).sum(:value)
Run Code Online (Sandbox Code Playgroud)

我想在一个查询中执行这些,相当于以下SQL

SELECT
  order_types.id, Count(*) as total_count, Sum(orders.value) As total_value
FROM
  order
JOIN
  order_types ON orders.order_type_id = order_types.ID
GROUP BY
  order_types.id
Run Code Online (Sandbox Code Playgroud)

查询还应返回完整OrderType对象,以便在视图中显示名称

Len*_*ran 11

由于ActiveRecord在同一查询中不支持多个聚合函数,因此需要执行一些原始SQL来实现此目的.

grouped_sales = OrderType
  .select('order_types.id, order_types.name, 
     sum(orders.value) as sale, count(*) as purchase')
  .join('JOIN orders ON orders.order_type_id = order_types.id')
  .group('order_types.id')
Run Code Online (Sandbox Code Playgroud)

这里要注意的是,您需要使用OrderType中的现有列作为聚合列的别名.在这里,您还将获得OrderType对象.

要访问结果:

id -> grouped_sales.first.id
name -> grouped_sales.first.name
total orders -> grouped_sales.first.sale
order value -> grouped_sales.first.purchase
Run Code Online (Sandbox Code Playgroud)


Ale*_*ndr 6

现在 pluck+arel 就可以完成这项工作。

model = Model.arel_table
Model.group(:order_type).pluck(model[:id].count, model[:value].sum)
Run Code Online (Sandbox Code Playgroud)

如果按 ID 应用了默认排序,则可能还需要附加 .order(:order_type) 。


Woj*_*ski 5

甚至有更好的解决方案:

.pluck('sum(orders.value), count(*)').first