我有一个适用于Postgres v10的SQL查询。
SELECT *
FROM
(
SELECT DISTINCT ON (title) products.title, products.*
FROM "products"
) subquery
WHERE subquery.active = TRUE AND subquery.product_type_id = 1
ORDER BY created_at DESC
查询的目标是根据title
列进行区分,然后对其进行过滤和排序。 (我首先使用了子查询,因为似乎没有子查询就无法将DISTINCT ON
与ORDER BY
组合在一起。
我正在尝试在ActiveRecord中表达上述查询。
我一直在做
Product.select("*")
.from(Product.select("DISTINCT ON (product.title) product.title, meals.*"))
.where("subquery.active IS true")
.where("subquery.meal_type_id = ?", 1)
.order("created_at DESC")
,那行得通!但是,其中的字符串where子句相当混乱。是否有更好的方法可以使用ActiveRecord / Arel来表达此查询,还是我刚刚遇到ActiveRecord可以表达的限制?
答案 0 :(得分:1)
我认为ActiveRecord调用可以得到改善。
但是我将首先从原始SQL查询开始改进。
子查询
SELECT DISTINCT ON (title) products.title, products.* FROM products
(我认为应该代替meals
而不是products
)具有重复的products.title
,在这里没有必要。更糟糕的是,它错过了ORDER BY子句。正如PostgreSQL documentation所说:
请注意,除非使用ORDER BY来确保所需行排在最前面,否则每个集合的“第一行”都是不可预测的
我会将子查询重写为:
SELECT DISTINCT ON (title) * FROM products ORDER BY title ASC
给我们打电话:
Product.select('DISTINCT ON (title) *').order(title: :asc)
在主查询where
中,调用使用subquery
的Rails生成的别名。我不会在别名子查询上依赖Rails内部约定,因为它可能随时更改。如果您不考虑这一点,则可以使用哈希样式参数语法在一个where
调用中合并这些条件。
最终结果:
Product.select('*')
.from(Product.select('DISTINCT ON (title) *').order(title: :asc))
.where(subquery: { active: true, meal_type_id: 1 })
.order('created_at DESC')