I am using Rails 4.2 with PostgreSQL. I have a Product
model and a Purchase
model with Product
has many
Purchases
. I want to find the distinct recently purchased products. Initially I tried:
Product.joins(:purchases)
.select("DISTINCT products.*, purchases.updated_at") #postgresql requires order column in select
.order("purchases.updated_at DESC")
This however results in duplicates because it tries to find all tuples where the pair (product.id
and purchases.updated_at
) has a unique value. However I just want to select the products with distinct id
after the join. If a product id appears multiple times in the join, only select the first one. So I also tried:
Product.joins(:purchases)
.select("DISTINCT ON (product.id) purchases.updated_at, products.*")
.order("product.id, purchases.updated_at") #postgres requires that DISTINCT ON must match the leftmost order by clause
This doesn't work because I need to specify product.id
in the order
clause because of this constraint which outputs unexpected order.
What is the rails way to achieve this?
To build on erwin-brandstetter's answer, this is how you could do this with ActiveRecord (should be close at least):
Use a subquery and add a different
ORDER BY
clause in the outerSELECT
:Details for
DISTINCT ON
:Or some other query technique:
But if all you need from
Purchases
isupdated_at
, you can get this cheaper with a simple aggregate in a subquery before you join:About
NULLS LAST
:Or even simpler, but not as fast while retrieving all rows:
Product.id
needs to be defined as primary key for this to work. Details:If you fetch only a small selection (with a
WHERE
clause restricting to just one or a fewpr.id
for instance), this will be faster.So building on @ErwinBrandstetter answer, I finally found the right way of doing this. The query to find distinct recent purchases is
The
order_by
isn't needed inside the subquery, since we are anyway ordering in the outer query.The rails way of doing this is -
The second (and better) way to do this as suggested by @ErwinBrandstetter is
which can written in rails as
Try to do this:
I ended up with this -
Still looking for a better way to do this.