【问题标题】:Rank rows within grouped by (2 columns)对分组内的行进行排名(2 列)
【发布时间】:2021-03-24 06:39:54
【问题描述】:

我写了一个查询来获取这样的数据(附图),user_id 和 topic_id 被分组并计算分数的平均值。我想对每个用户的分数进行排名,因此每个用户的最高 topic_id 排名为 1。我们如何编写查询来对他们的分数进行排名,因为我需要为每个用户选择第一行。

表格是这样的 -

USER_ID        TOPIC_ID    SCORE  
------------- ------------- ------ 
 b33e3100a7be  829e4b89c318  85     
 b33e3100a7be  b19b6f2b2975  82     
 b33e3100a7be  e305c970701c  81.6   
 b33e3100a7be  6c6fac161e65  81.6   
 7379ce6bc5a9  6c6fac161e65  54.6   
 7379ce6bc5a9  e305c970701c  54.6   
 7379ce6bc5a9  b19b6f2b2975  51.6 

并希望输出看起来像这样。

 USER_ID        TOPIC_ID    SCORE  RANK
------------- ------------- ------ -----
 b33e3100a7be  829e4b89c318  85     1
 b33e3100a7be  b19b6f2b2975  82     2
 b33e3100a7be  e305c970701c  81.6   3
 b33e3100a7be  6c6fac161e65  81.6   3
 7379ce6bc5a9  6c6fac161e65  54.6   1
 7379ce6bc5a9  e305c970701c  54.6   1
 7379ce6bc5a9  b19b6f2b2975  54.6   2

enter image description here

【问题讨论】:

    标签: sql postgresql subquery sql-order-by greatest-n-per-group


    【解决方案1】:

    您可以使用窗口函数获得所有最高分:

    select t.*
    from (select t.*,
                 rank() over (partition by user_id order by score desc) as seqnum
          from t
         ) t
    where seqnum = 1;
    

    在这种情况下,rank() 返回所有最高的主题,如果有平局的话。 row_number() 任意返回一个。

    您还可以使用相关子查询:

    select t.*
    from t
    where t.score = (select max(t2.score)
                     from t t2
                     where t2.user_id = t.user_id
                    );
    

    请注意,这两种方法都可以合并到聚合查询中。无需保存中间结果即可获得您想要的结果。

    【讨论】:

      【解决方案2】:

      您可以使用 distinct on 获得每次使用的最高分行:

      select distinct on (user_id) t.*
      from mytable t
      order by user_id, score desc
      

      如果您要显示您正在开始的数据,以及您用来生成所显示的中间结果集的查询,我们可能会进一步优化代码。您可能想为此提出一个新问题,提供适当的示例数据、所需结果和现有代码。

      如果你想允许平局,那么你可以使用rank():

      select *
      from (
          select t.*,
              rank() over(partition by user_id order by score desc) rn
          from mytable t
      ) t
      where rn = 1
      

      或者,在 Postgres 13 中:

      select t.*
      from mytable t
      order by rank() over(partition by user_id order by score desc)
      fetch first 1 row with ties
      

      【讨论】:

      • 我已经编辑了问题、示例表和添加到其中的输出。
      • 但是如果用户有 2 个不同的主题,并且两者的分数相同,并且它们是该用户的前两行,我需要两行而不是一行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2016-04-05
      相关资源
      最近更新 更多