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

PostgreSQL中如何获取分组后前2个唯一name对应的全量数据

搞定PostgreSQL:获取前2个唯一分组的所有符合条件数据

我来帮你解决这个查询问题!先理清楚你的场景:

你有一张customers表,结构是这样的:

create table customers (id text, name text, number int, useless text);

已经插入了这些数据:

insert into customers (id, name, number, useless) values 
('1','apple',1, 'a'), 
('2','banana',3, 'b'), 
('3','pear',2, 's'), 
('4','apple',1,'e'), 
('5','banana',3,'s'), 
('6','cherry',3, 'a'), 
('7','cherry',4, 's'), 
('8','apple',2, 'd'), 
('9','banana',4, 'c'), 
('10','pear',5, 'e');

先说说你之前的问题

你第一次写的查询失败,是因为PostgreSQL的GROUP BY规则要求所有非聚合列都要出现在分组条件里(除非你调整了宽松的配置,但这不是最佳实践),而且你的需求根本不是分组聚合,而是要先拿到前2个唯一的name分组,再取出这些分组下所有满足number < 4的数据。

你的第二次尝试用窗口函数的思路是对的,但没关联原表的完整数据,也没加上number <4的过滤条件,所以才没得到预期结果。

两种正确的实现方式

方式一:用子查询+JOIN(逻辑直观)

SELECT c.id, c.name, c.number, c.useless
FROM customers c
JOIN (
    -- 先获取按name排序的前2个唯一分组
    SELECT DISTINCT name
    FROM customers
    ORDER BY name
    LIMIT 2
) AS top_names ON c.name = top_names.name
WHERE c.number < 4
ORDER BY c.name;

方式二:用窗口函数(扩展性更强)

SELECT id, name, number, useless
FROM (
    SELECT 
        *,
        -- 给每个唯一的name分配排名,按name排序
        DENSE_RANK() OVER (ORDER BY name) AS name_rank
    FROM customers
    WHERE number < 4 -- 先过滤数据,提升效率
) AS ranked_customers
WHERE name_rank <= 2
ORDER BY name;

为什么这两种方式能行?

  • 方式一:先通过子查询拿到前2个唯一的name(按字母顺序排序),再关联原表,筛选出这些分组下number <4的所有记录,逻辑简单易懂。
  • 方式二:先过滤掉number >=4的数据(减少后续计算量),然后用DENSE_RANK()给每个name分配相同的排名,最后只保留排名前2的分组数据,这种方式如果后续要取前N个分组,只需要修改name_rank <= 2里的数字就行,非常灵活。

两种方式都会返回你预期的结果:

('1','apple',1, 'a'), ('4','apple',1,'e'), ('8','apple',2, 'd'), ('2','banana',3, 'b'), ('5','banana',3,'s')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:41:18