按集合函数

时间:2017-05-18 21:32:43

标签: sql ruby-on-rails postgresql

我有场地和场地有很多项目。我想获得每个场地的最新项目。要在单个查询中返回每个场地的最新项目,我可以使用max aggregate函数和group by:

class Item < ActiveRecord::Base
  scope :newest_items, -> (venue_ids) {
    select('max(items.id) as id, venue_id').joins(:venue).where('venues.id IN (?)', venue_ids).group(:venue_id)
  }
end

生成的sql:

Item.newest_items(Venue.pluck(:id)).to_sql 
 => "SELECT max(items.id) as id, venue_id FROM \"items\" 
    INNER JOIN \"venues\" ON \"venues\".\"id\" = \"items\".\"venue_id\" 
    WHERE (venues.id IN (1,2,3)) 
    GROUP BY \"items\".\"venue_id\"" 

所以每个场地都有最新的项目。但结果是,我想按照创建日期对结果进行排序。

如果我有订购条款:

 class Item < ActiveRecord::Base
  scope :newest_items, -> (venue_ids) {
    select('max(items.id) as id, venue_id')
    .joins(:venue).where('venues.id IN (?)', venue_ids)
    .group(:venue_id).order('items.created_at desc')
  }
end

sql:

Item.close_by_items(Venue.pluck(:id)).to_sql
=> "SELECT max(items.id) as id, venue_id 
    FROM \"items\" INNER JOIN \"venues\" ON \"venues\".\"id\" = \"items\".\"venue_id\" 
    WHERE (venues.id IN (1,2,3)) 
    GROUP BY \"items\".\"venue_id\" 
    ORDER BY items.created_at desc" 

我收到错误:

ActiveRecord :: StatementInvalid:PG :: GroupingError:ERROR:column&#34; items.created_at&#34;必须出现在GROUP BY子句中或用于聚合函数

为什么created_at必须出现在GROUP BY子句中或者在聚合函数中使用?我想要做的就是使用created_at time命令group by子句的结果。

2 个答案:

答案 0 :(得分:0)

如果您只希望每个地点使用一个项目,则可以使用DISTINCT ON代替分组。

class Item < ActiveRecord::Base
  def self.newest_items(*venues)
    select('DISTINCT ON(items.venue_id), items.*')
      .where(venue_id: *venues)
      .order('items.created_at DESC')
  end
end

答案 1 :(得分:0)

实现此目的的另一种方法是将ORDER置于子查询中,类似这样的东西应该按预期工作:

Item.close_by_items(Venue.pluck(:id)).to_sql
=> "SELECT max(sub.id) as id, sub.venue_id FROM (SELECT items.id, venue_id 
    FROM \"items\" INNER JOIN \"venues\" ON \"venues\".\"id\" = \"items\".\"venue_id\" 
    WHERE (venues.id IN (1,2,3)) ORDER BY items.created_at desc") AS sub
    GROUP BY \"sub\".\"venue_id\"