说我有一个看起来像这样的表:
| 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&以某种方式限制。
我完全不确定从哪里开始或谷歌的关键词是什么。我会对正确方向的一些推动感到满意,所以我可以自己找到答案,或者给出完整的答案。
答案 0 :(得分:0)
window function row_number()
的另一种情况。
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;
如果你想追加剩下的行(你的问题会变得模糊,如果和如何):
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行排在第一位,其余的排在后面。
或使用CTE和UNION 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
。