【问题标题】:How to query for records based on a group and ordering?如何根据组和排序查询记录?
【发布时间】:2012-08-22 01:43:31
【问题描述】:

鉴于以下模型:

User
    id
UserPulses
    id, user_id, group_id, created_at

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

类似: user.user_pulses.group("group_id)")

有什么想法吗?谢谢

【问题讨论】:

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


    【解决方案1】:

    您无法通过通常的 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 = 1)and peels off the originaluser_pulses` 列。

    【讨论】:

    • 谢谢,尝试通过它调试。收到错误“PG::Error: ERROR: syntax error at or near ":" LINE 7: where user_id = :user_id "
    • 这似乎返回了一个数组,这意味着我不能做 pulses.where(:group_id => 1) 从数组中获取记录而无需请求数据库。有没有办法从这个数组中提取一个项目?
    • @AnApprentice:find_by_sql 希望您在使用占位符时将参数包装在一个数组中。我刚刚添加了缺少的[]。对此感到抱歉。
    • @AnApprentice:你必须手动将这种东西添加到 SQL 中,ActiveRecord 并不真正理解比select * from t where a = b 更复杂的东西。
    【解决方案2】:

    您可以使用 PostgreSQL 特定的 SQL 扩展功能DISTINCT: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

    【讨论】:

      【解决方案3】:

      也许是这样的。但是,如果用户/组 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
      

      【讨论】:

      • 在大多数情况下,每个用户/组 ID 每天会有多条记录。建议?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      相关资源
      最近更新 更多