我将 Rails 4.2 与 PostgreSQL 结合使用。我有一个 Product
模型和一个 Purchase
模型,其中 Product
has many
Purchases
。我想找到不同的最近购买的产品。最初我试过:
Product.joins(:purchases)
.select("DISTINCT products.*, purchases.updated_at") #postgresql requires order column in select
.order("purchases.updated_at DESC")
然而,这会导致重复,因为它会尝试查找对(product.id
和 purchases.updated_at
)具有唯一值的所有元组。但是,我只想在加入后选择具有不同 id
的产品。如果产品 ID 在连接中出现多次,则只选择第一个。所以我也尝试了:
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,我需要在 order
子句中指定 product.id
输出意外顺序的约束。
rails 的实现方式是什么?
最佳答案
基于@ErwinBrandstetter 的回答,我终于找到了正确的方法。查找不同的最近购买的查询是
SELECT *
FROM (
SELECT DISTINCT ON (pr.id)
pu.updated_at, pr.*
FROM Product pr
JOIN Purchases pu ON pu.product_id = pr.id
) sub
ORDER BY updated_at DESC NULLS LAST;
子查询中不需要 order_by
,因为我们无论如何都在外部查询中排序。
rails 的做法是 -
inner_query = Product.joins(:purchases)
.select("DISTINCT ON (products.id) products.*, purchases.updated_at as date") #This selects all the unique purchased products.
result = Product.from("(#{inner_query.to_sql}) as unique_purchases")
.select("unique_purchases.*").order("unique_purchases.date DESC")
@ErwinBrandstetter 建议的第二种(也是更好的)方法是
SELECT *
FROM Product pr
JOIN (
SELECT product_id, max(updated_at) AS updated_at
FROM Purchases
GROUP BY 1
) pu ON pu.product_id = pr.id
ORDER BY pu.updated_at DESC NULLS LAST;
在rails中可以写成
join_query = Purchase.select("product_id, max(updated_at) as date")
.group(1) #This selects most recent date for all purchased products
result = Product.joins("INNER JOIN (#{join_query.to_sql}) as unique_purchases ON products.id = unique_purchases.product_id")
.order("unique_purchases.date")
关于sql - Rails - 加入后不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32775220/