返回一列上不同的记录,但按另一列排序

时间:2014-04-25 01:46:52

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

我正在使用非常标准的消息模型构建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订购。

1 个答案:

答案 0 :(得分:2)

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;

也可能更慢。