Reputation: 599
Need to build a "Top 10" query that works with SQLite and Postgres.
Client model
Client has_many :merchandises, :through => :orders, :source => :items
I want to group merchandises ordered by product_id, get the count for each and sort by most product ordered top and limit to 10.
Client.last.merchandises.group(:product_id).count(:quantity)
SELECT COUNT("items"."quantity") AS count_quantity, product_id AS product_id FROM "items" INNER JOIN "orders" ON "items"."order_id" = "orders"."id" WHERE "orders"."client_id" = 2 GROUP BY product_id
=> {1=>91, 2=>1, 12=>1, 32=>1, 33=>1, 34=>1, 37=>1, 75=>1, 84=>1, 85=>1}
What's missing: sort by, limit to 10 and get product.name along with quantity count
Latest development:
Items are selected but need to show product.name
class Client < ActiveRecord::Base
def top_ten_products
Item.find_by_sql(
"SELECT i.product_id, sum(i.quantity) AS sum_quantity
FROM orders o
JOIN items i ON i.order_id = o.id
WHERE o.client_id = 2
GROUP BY 1
ORDER BY 2 DESC
LIMIT 10;"
)
end
Console output
=> [#<Item product_id: 1>, #<Item product_id: 37>, #<Item product_id: 75>, #<Item product_id: 12>, #<Item product_id: 32>, #<Item product_id: 33>, #<Item product_id: 2>, #<Item product_id: 34>, #<Item product_id: 84>, #<Item product_id: 85>]
Client#show
<%= @client.top_ten_products %>
Upvotes: 0
Views: 628
Reputation: 658997
Assuming that product_id
is a column of table items
, the query could look like this in PostgreSQL:
SELECT i.product_id
,p.name
,sum(i.quantity) AS sum_quantity
FROM orders o
JOIN items i ON i.order_id = o.id
LEFT JOIN product p USING (product_id)
WHERE o.client_id = 2
GROUP BY 1,2
ORDER BY 3 DESC, 2 -- with same quantity, order by name
LIMIT 10;
I changed your quantity aggregation to a sum
and added a commented column for count
, as I suspect you mistakenly had a count where you want a sum.
sum()
is confirmed.
Included name from table product per request.
LEFT JOIN
is just a precaution for missing entries in table product
, if referential integrity is guaranteed, it can be a plain JOIN
instead.
Upvotes: 1