【问题标题】:Return records distinct on one column but order by another column返回在一个列上不同但按另一列排序的记录
【发布时间】:2014-06-10 13:30:45
【问题描述】:

我正在使用非常标准的消息模型构建 Rails 3 应用程序。我想为每个唯一的 conversation_id 返回最近创建的消息记录。这似乎是一项相当简单的任务,但我无法编写代码或找到可行的解决方案。
诚然,我也不是超级精通 SQL(到目前为止,我主要使用 Active Record 查询)。这是我想要完成的任务。

示例消息表:

| id | sender_id | receiver_id | conversation_id | subject | body | created_at |
| 1  |     *     |      *      |        1        |    *    |   *  |    16:01   |
| 2  |     *     |      *      |        2        |    *    |   *  |    17:03   |
| 3  |     *     |      *      |        1        |    *    |   *  |    18:04   |
| 4  |     *     |      *      |        3        |    *    |   *  |    19:06   |
| 5  |     *     |      *      |        2        |    *    |   *  |    20:07   |
| 6  |     *     |      *      |        1        |    *    |   *  |    21:08   |
| 7  |     *     |      *      |        4        |    *    |   *  |    22:09   |

返回我只想获取每个conversation_id 并按created_at DESC 排序的“最近”消息记录:

| id | sender_id | receiver_id | conversation_id | subject | body | created_at |
| 7  |     *     |      *      |        4        |    *    |   *  |    22:09   |
| 6  |     *     |      *      |        1        |    *    |   *  |    21:08   |
| 5  |     *     |      *      |        2        |    *    |   *  |    20:07   |
| 4  |     *     |      *      |        3        |    *    |   *  |    19:06   |

我在 SQLite 中的原始解决方案运行良好:GROUP BY (conversation_id)。但是,显然该解决方案是 SQLite 独有的,不适用于 Postgres。

接下来,我尝试了:SELECT DISTINCT ON (conversation_id) *。但是,这也需要我不想要的ORDER BY (conversation_id)。我想通过created_at订购。

【问题讨论】:

    标签: sql postgresql ruby-on-rails-3.2 sql-order-by greatest-n-per-group


    【解决方案1】:

    DISTINCT ON

    如果你使用DISTINCT ON,你需要一个子查询:

    SELECT *
    FROM  (
       SELECT DISTINCT ON (conversation_id) *
       FROM   message t
       ORDER  BY conversation_id, created_at DESC
       ) sub
    ORDER BY created_at DESC;
    

    子查询中的顺序必须与DISTINCT ON 子句中的列一致,因此您必须将其包装在外部查询中才能达到您想要的排序顺序。

    替代row_number()

    类似的故事,你也需要一个子查询:

    SELECT id, sender_id, receiver_id, conversation_id, subject, body, created_at
    FROM  (
       SELECT *, row_number() OVER (PARTITION BY conversation_id
                                    ORDER BY created_at DESC) AS rn
       FROM   message t
       ) sub
    WHERE  rn = 1
    ORDER  BY created_at DESC;
    

    也可能更慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-11
      • 2018-10-23
      • 1970-01-01
      • 1970-01-01
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 2022-01-09
      相关资源
      最近更新 更多