按列分组分组

时间:2014-08-18 13:03:28

标签: sql postgresql sql-order-by window-functions

说我有一个看起来像这样的表:

| id | category_id | created_at |
| 1  |     3       | date...    |
| 2  |     4       | date...    |
| 3  |     1       | date...    |
| 4  |     2       | date...    |
| 5  |     5       | date...    |
| 6  |     6       | date...    |

想象一下,还有更多的参赛作品。我想以一种新鲜的方式抓住这些,所以按created_at DESC排序 - 但我也想按类别对它们进行分组,每组3个!

所以在伪代码中它看起来像这样:

Go to category 1
-> Pick last 3
Go to category 2
-> Pick last 3
Go to category 3
-> Pick last 3

等等,从category_id 1开始,当没有其他类别可以从中获取时。然后这将被分页,所以我需要使它与offset&以某种方式限制。

我完全不确定从哪里开始或谷歌的关键词是什么。我会对正确方向的一些推动感到满意,所以我可以自己找到答案,或者给出完整的答案。

1 个答案:

答案 0 :(得分:0)

window function row_number()的另一种情况。

每个类别最新的3行

SELECT id, category_id, created_at
FROM  (
   SELECT id, category_id, created_at
        , row_number() OVER (PARTITION BY category_id
                             ORDER BY created_at DESC) AS rn
   FROM   tbl
   ) sub
WHERE  rn < 4
ORDER  BY category_id, rn;

每个类别最新的3行,加上后面的行

如果你想追加剩下的行(你的问题会变得模糊,如果和如何):

SELECT *
FROM  (
   SELECT id, category_id, created_at
        , row_number() OVER (PARTITION BY category_id
                             ORDER BY created_at DESC) AS rn
   FROM   tbl
   ) sub
ORDER  BY (rn > 3), category_id, rn;

可以按boolean表达式(rn > 3)的结果排序:
FALSE(0)
TRUE(1)
NULL(因为默认为NULLS LAST - 此处不适用)

这样,每个类别最新的3行排在第一位,其余的排在后面。

使用CTEUNION ALL

WITH cte AS (
   SELECT id, category_id, created_at
        , row_number() OVER (PARTITION BY category_id
                             ORDER BY created_at DESC) AS rn
   FROM   tbl
   )
)
SELECT id, category_id, created_at
FROM   cte
WHERE  rn < 4
ORDER  BY category_id, rn
)
UNION  ALL
)
SELECT id, category_id, created_at
FROM   cte
WHERE  rn >= 4
ORDER  BY category_id, rn
);

同样的结果。
所有括号都需要ORDER BY查询的各个页面中附加UNION