Select 每个人的前 4 名得分,但至少需要两个位置

Select top 4 scores by person but need at least two locations

我有这样的数据

eventId locationId score athlete
8739    73          48  matt
8734    73          46  matt
8788    73          45  matt
8738    73          44  matt
8787    73          44  matt
8735    73          43  matt
8789    6           43  matt

我需要按人获取前 4 个分数,但前 4 个分数中至少有 1 个需要来自与其他 3 个不同的 locationId

在这种情况下,我想要这个 returned

eventId locationId score athlete
8739    73          48  matt
8734    73          46  matt
8788    73          45  matt
8789    6           43  matt

我试过写出使用 GROUP BY HAVING MIN(locationId) != MAX(locationId) 的查询,但我不确定如何在使用 ORDER BYLIMIT 的同时完成它。

我也尝试过自连接,但我不确定如何根据 s.scorescore2.[=20= return 获得最佳结果]

似乎在正确轨道上的自我加入的开始

SELECT s.eventid, s.locationid, athlete, score
, s2.eventid, s2.locationid, s2.athlete, score score2
FROM singles s
  INNER JOIN singles s2 ON s.athlete = s2.athlete AND s.locationid != s2.locationid
WHERE s.athlete = 'matt'
ORDER BY score DESC;

您可以使用 row_number 分析函数和 limit 子句,其中包括一个 self-join,如下所示

select locationId, score, athlete
 from
   (
    select locationId, score, athlete, rn, rn2
      from(
            select *
              from
              (
                 with singles(locationId, score, athlete) as
                 (
                  select 73, 48, 'matt' union all
                  select 73, 46, 'matt' union all
                  select 73, 45, 'matt' union all
                  select 73, 44, 'matt' union all
                  select 73, 44, 'matt' union all
                  select 73, 43, 'matt' union all
                  select  6, 43, 'matt'     
                 )
                 select row_number() over (partition by s.locationId order by s.score desc) as rn,
                        row_number() over (partition by s2.locationId order by s2.score desc) as rn2,
                        s.athlete, s.locationId, s.score
                   from singles s join singles s2 
                     on s.score = s2.score
                  where s.athlete = 'matt'
               ) q1
               order by score desc, rn, rn2 
            ) q2 
      group by locationId, score
     having sum(rn) <= sum(rn2)
      order by rn, score desc
      limit 4
   ) q3
 order by score desc

dbfiddle.uk demo

所以,你真正想要的是前三名,然后是保证至少两个位置的第一个分数。

这是一个相当困难的条件,但我认为这可以解决问题:

with s as (
      select t.*,
             row_number() over (partition by athlete order by score desc) as seqnum
      from t
     ),
     s3 as (
      select s.*
      from s
      where seqnum <= 3
     )
select *
from s3
union all
(select s.*
 from s
 where ( (select count(distinct locationid) from s3) > 1 and seqnum = 4 ) or
       ( (select count(distinct locationid) from s3) = 1 and
         seqnum = (select min(seqnum)
                   from s
                   where locationid not in (select locationid from s3)
                  )
       )
);

Here 是一个 db<>fiddle.