如何根据组和排序查询记录?

时间:2012-08-22 01:43:31

标签: sql ruby-on-rails ruby-on-rails-3 postgresql activerecord

鉴于以下模型:

User
    id
UserPulses
    id, user_id, group_id, created_at

我想要做的是获取按(group_id)分组的所有用户的UserPulses,并且每个group_id仅获取最新的UserPulse。我已经能够通过逐个循环遍历这样做,但这需要大量的查询。这可以用一个查询吗?

像:     user.user_pulses.group( “GROUP_ID)”)

有什么想法吗?感谢

3 个答案:

答案 0 :(得分:2)

您不能通过通常的ActiveRecord接口可靠地执行此操作,但您可以使用window function通过SQL执行此操作。你想要一些像这样的SQL:

select id, user_id, group_id, created_at
from (
    select id, user_id, group_id, created_at, 
           row_number() over (partition by group_id order by created_at desc, id desc) as r
    from user_pulses
    where user_id = :user_id
) dt
where r = 1

然后将其换成find_by_sql

pulses = UserPulses.find_by_sql([%q{
    select id, user_id, group_id, created_at
    from (
        select id, user_id, group_id, created_at, 
               row_number() over (partition by group_id order by created_at desc, id desc) as r
        from user_pulses
        where user_id = :user_id
    ) dt
    where r = 1
}, :user_id => user.id])

窗口函数部分基本上对每个group_id执行本地GROUP BY,对它们进行排序(使用id desc作为辅助排序键作为“以防万一”绑定断路器),并对每个进行排序 - r中的组行号。然后外部查询过滤掉每个组中的第一个(where r = 1and peels off the original user_pulses`列。

答案 1 :(得分:2)

您可以使用SQL功能DISTINCT的PostgreSQL特定扩展:DISTINCT ON

SELECT DISTINCT ON (group_id)
       id, user_id, group_id, created_at
FROM   user_pulses
WHERE  user_id = :user_id
ORDER  BY group_id, created_at DESC, id; -- id just to break ties

比窗口功能更简单(但不是便携式),可能最快 更多details under this related question

答案 2 :(得分:0)

也许是这样的。但如果用户/ group_id组合共享相同的日期,则可能有多条记录。

SELECT p.id, p.user_id, p.group_id, p.created_at
  FROM UserPulses p
      ,( SELECT user_id, group_id, MAX(created_at) as max_date
           FROM UserPulses
           GROUP BY user_id, group_id ) m
  WHERE u.user_id = m.user_id
    AND u.group_id = m.group_id
    AND u.created_at = m.max_date