You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL技术需求:按name分组查询每组最低的3个score记录

PostgreSQL按分组获取每组最低分的3条记录

问题场景

现有results表,结构包含id(int)、name(varchar)、score(int),表数据如下:

id   name   score
1    x      5
2    x      9
3    x      10
5    x      2
85   y      20
2    y      1
9    z      98
2    z      6
7    z      93
10   z      9

需求:按name分组,查询每组中score最低的3条记录,期望输出:

id   name   score
1    x      5
2    x      9
5    x      2
85   y      20
2    y      1
2    z      6
7    z      93
10   z      9

原SQL的问题

你尝试的SQL存在两个核心问题:

  1. GROUP BY用法错误:使用GROUP BY name时,SELECT列表中的id和score没有聚合函数(如MIN/MAX),PostgreSQL不允许这种非标准写法,会导致语法错误或返回不可预期的结果。
  2. 全局LIMIT不符合需求:LIMIT 3是限制整个查询返回3条记录,而非每组返回3条,完全无法实现分组取数的目标。

正确解决方案

使用PostgreSQL的窗口函数可以轻松实现分组内的TopN查询,这里推荐两种方式:

方式1:使用ROW_NUMBER()(严格取每组前3条,同score会按行号区分)

SELECT id, name, score
FROM (
    SELECT 
        id, 
        name, 
        score,
        -- 按name分区,每个分区内按score升序编号
        ROW_NUMBER() OVER (PARTITION BY name ORDER BY score ASC) AS row_num
    FROM results
) ranked_results
-- 筛选每个分区内编号前3的记录
WHERE row_num <= 3
-- 按name和score排序,和期望输出对齐
ORDER BY name, score;

方式2:使用RANK()(保留同score的并列记录)

如果存在相同score的记录,希望所有并列的最低分都被保留(比如某组有4条记录score相同且都是最低,会全部返回),可以用RANK()替代ROW_NUMBER():

SELECT id, name, score
FROM (
    SELECT 
        id, 
        name, 
        score,
        RANK() OVER (PARTITION BY name ORDER BY score ASC) AS rank_num
    FROM results
) ranked_results
WHERE rank_num <= 3
ORDER BY name, score;

结果验证

执行上述SQL后,会得到与你期望完全一致的输出:

  • x组返回score最低的3条:2(id5)、5(id1)、9(id2)
  • y组仅有2条记录,全部返回
  • z组返回score最低的3条:6(id2)、9(id10)、93(id7)

内容的提问来源于stack exchange,提问作者Tmiskiewicz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:45:25