在Postgres中使用子查询正确格式化ActiveRecord查询

时间:2018-10-25 14:56:19

标签: ruby-on-rails postgresql activerecord

我有一个适用于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 ONORDER 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可以表达的限制?

1 个答案:

答案 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')