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

PostgreSQL按年龄分组查询各分组Top10邮箱域名问题排查

问题根因

你编写的排名逻辑未按年龄组分区排名,而是对全量所有年龄组的域名统一排序,才会出现筛选排名<=10仅覆盖单个年龄组的错误。


修正后查询(两种业务场景可选)

场景1:每组严格返回最多10条,并列域名随机取(总结果最多50行,符合预期输出要求)

如果要求5个年龄组加起来最多50行,不需要保留并列排名,直接用row_number()并在窗口函数中添加PARTITION BY agegroup按年龄组分区:

with users as (
    select a.*, 
      extract(year from age(dob)) age,
      substr(email, position('@' in email)+1, 1000) domain
    from user_table a
   ),
   useragegroup as (
    select a.*,
     case when age between 0 and 18 then '0-18'
          when age between 19 and 29 then '19-29'
          when age between 30 and 49 then '30-49' 
          when age between 50 and 65 then '50-65'
          else '66-up'
     end agegroup
    from users a
   ),
   rank as (
     select agegroup, domain, count(*) as user_cnt,
       -- 核心修正:添加PARTITION BY agegroup实现按年龄组内独立排名
       row_number() over (partition by agegroup order by count(*) desc) r
     from useragegroup a
     group by agegroup, domain
   )
   select a.*
   from rank a
   where r<=10;

场景2:每组保留并列排名,最多10个名次(单组可能超过10条,总结果>50行)

如果需要保留相同计数域名的并列排名,换用dense_rank()即可,此时同组排名第10的域名有多少个就返回多少个,不会截断:

with users as (
    select a.*, 
      extract(year from age(dob)) age,
      substr(email, position('@' in email)+1, 1000) domain
    from user_table a
   ),
   useragegroup as (
    select a.*,
     case when age between 0 and 18 then '0-18'
          when age between 19 and 29 then '19-29'
          when age between 30 and 49 then '30-49' 
          when age between 50 and 65 then '50-65'
          else '66-up'
     end agegroup
    from users a
   ),
   rank as (
     select agegroup, domain, count(*) as user_cnt,
       dense_rank() over (partition by agegroup order by count(*) desc) r
     from useragegroup a
     group by agegroup, domain
   )
   select a.*
   from rank a
   where r<=10;

测试数据注意事项

你提供的测试插入语句所有用户dob都固定为2005-01-01,计算年龄后只会落在单个年龄组,测试时需要调整dob生成逻辑,覆盖所有5个年龄组:

insert into user_table (
    first, last, email, dob
)
select
    left(md5(i::text), 3),
    left(md5(random()::text), 3),
    'user_' || i || '@' || (
    CASE (RANDOM() * 14)::INT
      WHEN 0 THEN 'gmail'
      WHEN 1 THEN 'hotmail'
      WHEN 2 THEN 'apple'
      WHEN 3 THEN 'icloud'
      WHEN 4 THEN 'aol'
      WHEN 5 THEN 'usa'
      WHEN 6 THEN 'govt'
      WHEN 7 THEN 'stackoverflow'
      WHEN 8 THEN 'random'
      WHEN 9 THEN 'domain'
      WHEN 10 THEN 'subby'
      WHEN 11 THEN 'youtube'
      WHEN 12 THEN 'google'
      WHEN 13 THEN 'triple'
      WHEN 14 THEN 'pixar'
    END
  ) || '.com' AS email,
    -- 随机生成1950-2005年的出生日期,覆盖所有年龄组
    ('1950-01-01'::date + (random() * 20000)::int) as dob
from generate_series(1, 500) s(i);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 20:36:01