RoR / Postgres查询所有父项的第一个或最后一个子对象

时间:2012-07-02 23:39:06

标签: postgresql activerecord ruby-on-rails-3.1

我见过类似的问题,但没有完全符合我需要的答案。如果它在那里,我还没有看到它。我在Rails 3.1,Ruby 1.9.2上,部署在Heroku Cedar堆栈上(所以我使用的是postgres)

我有这个型号:

class User
  has_many :orders
end

class Order
  belongs_to :user

  #scope :last_for_each_user, ???
  #scope :first_for_each_user, ???

end

我需要范围(或方法)返回所有用户的第一个订单的所有订单,以及所有用户的最后订单的所有订单。我的第一直觉是使用GROUP BY,它适用于:SQLite3中的last_for_each_user,但Postgres不允许您选择不在GROUP BY子句中或作为聚合函数的一部分选择的列,我需要完全形成的订单对象(即所有列,订单。*)。

有什么想法吗?我不想选择整个表并在Ruby中对其进行排序。这感觉不对,在记忆中占了很多。

2 个答案:

答案 0 :(得分:1)

所以这就是我最终要做的事情,对于未来的头脑风暴:

scope :last_for_each_user, lambda {
  select("orders.*") & Order.select("max(orders.id) as id").group("orders.user_id")
}
scope :first_for_each_user, lambda {
  select("orders.*") & Order.select("min(orders.id) as id").group("orders.user_id")
}

如果有人有更好的想法,我非常愿意听到它。感谢整个SO社区(即使没有人回复),这是我第一次注册/提出问题,但每当我发现问题时,我都会在这里结束!

答案 1 :(得分:0)

您可以使用DISTINCT ON()规则来获取最后一个规则。以下是模型结构的示例:

scope :for_users, lambda {|ids, is_first| includes(:user).where("user_id IN (?)", ids).select("DISTINCT ON (users.id) *").order("orders.created_at ?", is_first ? : "ASC" : "DESC") }
scope :last_for_each_users, lambda { |users| for_each_users(users.map{|u| u.id }, false }
scope :first_for_each_users, lambda { |users| for_each_users(users.map{|u| u.id }, true }