products = Product.arel_table
orders = Order.arel_table
average_purchase_time = Arel::Nodes::Case.new.when(orders[:finished_at].not_eq(nil))
.then(orders[:finished_at] - orders[:created_at])
purchased = Arel::Nodes::Case.new.when(orders[:finished_at].not_eq(nil))
.then(1).else(0)
statement = products
.outer_join(orders)
.on(orders[:product_id].eq(products[:id]))
.project(products[:id].count(true).as('total'))
.project(purchased.sum.as('purchased'))
.project(average_purchase_time.average.as('average_purchase_time'))
Product.find_by_sql(statement.to_sql)
Explaining:
products = Product.arel_table
orders = Order.arel_table
When you call arel_table
for an ActiveRecord class, this will return an Arel::Table
object.
average_purchase_time = Arel::Nodes::Case.new.when(orders[:finished_at].not_eq(nil))
.then(orders[:finished_at] - orders[:created_at])
purchased = Arel::Nodes::Case.new.when(orders[:finished_at].not_eq(nil))
.then(1).else(0)
With Arel::Nodes::Case
, you can create an object that generates a CASE expression.
The method outer_join
is used to left join a table, that returns an Arel::SelectManager
object. Please remember to call the method on
with the ON clause.