如何使用 SQL 从每个组中获得最高得分球员?

Posted

技术标签:

【中文标题】如何使用 SQL 从每个组中获得最高得分球员?【英文标题】:How to get max scoring player from each group using SQL? 【发布时间】:2020-02-11 13:46:15 【问题描述】:

我有桌球员和比赛,我想找到得分最高的球员,请注意,如果得分匹配,则 ID 较低的球员是每个组的获胜者。

create table players (
      player_id integer not null unique,
      group_id integer not null
  );

  create table matches (
      match_id integer not null unique,
      first_player integer not null,
      second_player integer not null,
      first_score integer not null,
      second_score integer not null
  );



insert into players values(20, 2);
insert into players values(30, 1);
insert into players values(40, 3);
insert into players values(45, 1);
insert into players values(50, 2);
insert into players values(65, 1);
insert into matches values(1, 30, 45, 10, 12);
insert into matches values(2, 20, 50, 5, 5);
insert into matches values(13, 65, 45, 10, 10);
insert into matches values(5, 30, 65, 3, 15);
insert into matches values(42, 45, 65, 8, 4);

现在我想要结果

请注意,第一个和第二个玩家可以是同一组玩家。

结果:-

group_id | winner_id
  ----------+-----------
   1        | 45
   2        | 20
   3        | 40

我不确定如何继续。

【问题讨论】:

【参考方案1】:

以上都是正确的答案,只需提供所需的 90% 你可以在这里查看

https://www.db-fiddle.com/f/2Lp3LoMpXVefUbezRKBY3N/0

select group_id,player_id from
(
select
group_id
,P.player_id
,sum(points) as total
,DENSE_RANK () OVER ( 
            PARTITION BY group_id
            ORDER BY sum(points) desc, P.player_id asc
        )P_Rank 
from
(
select c.match_id, t.*
from matches c
  cross join lateral (
     values 
       (c.first_player, c.first_score),
       (c.second_player, c.second_score)
  ) as t(player, points)
order by match_id, points
) base
right join players P
on base.player = P.player_id
group by 1,2
order by 1
)BT
where P_Rank=1

【讨论】:

【参考方案2】:
SELECT GROUP_ID, PLAYER_ID, MAX_SCORE FROM (
SELECT GROUP_ID, PLAYER_ID, MAX_SCORE, DENSE_RANK() OVER(PARTITION BY GROUP_ID ORDER BY MAX_SCORE DESC,PLAYER_ID ASC) RANK
FROM
(
SELECT DISTINCT GROUP_ID, PLAYER_ID, COALESCE(MAX(TOT_SCORE)OVER (PARTITION BY PLAYER_ID),0)MAX_SCORE 
FROM 
(
SELECT PLAYER_ID, GROUP_ID, TOT_SCORE FROM 
   (
SELECT PLAYER, SUM(SCORE) AS TOT_SCORE
FROM 
     (
SELECT FIRST_PLAYER AS PLAYER,SUM(FIRST_SCORE)AS SCORE  FROM MATCHES GROUP BY FIRST_PLAYER
UNION 
SELECT SECOND_PLAYER AS PLAYER,SUM(SECOND_SCORE)AS SCORE  FROM MATCHES GROUP BY SECOND_PLAYER
      )
GROUP BY PLAYER 
   )S
RIGHT JOIN 
PLAYERS P
ON
S.PLAYER=P.PLAYER_ID
))) WHERE RANK=1

【讨论】:

【参考方案3】:

采取的方法:

对于表 2,我们将获得每个玩家的获胜者和相应分数 然后我们将玩家分组计算总和

上表将与表 1 连接后,将给出组中每个玩家的得分,我们将根据组和得分对这些数据进行排序

最后我们将选择每组的第一条记录,它将给出所需的结果

with actual_data as 
(select row_number()over(partition by group_id 
order by group_id asc, 
coalesce(table2.sum_score, 0) desc) as rn, 
group_id, player_id, coalesce(table2.sum_score, 0) as score 
from  players as table1
left join 
(select player, sum(score) as sum_score from ( 
select match_id, 
case 
when first_score > second_score then first_player
when first_score = second_score and first_player < second_player 
then first_player 
else second_player end as player, 
case 
when first_score > second_score then first_score 
when first_score = second_score and first_player < second_player 
then first_score 
else second_score end as score 
from matches) as foo 
group by player 
order by sum_score desc) as table2 
on table1.player_id = table2.player 
order by group_id asc,  coalesce(table2.sum_score, 0) desc 
) 
select group_id , player_id from actual_data where rn = 1

【讨论】:

【参考方案4】:

我认为最简单的方法是横向连接和distinct on:

select distinct on (p.group_id) p.group_id, v.player, v.score
from matches m cross join lateral
     (values (first_player, first_score), (second_player, second_score)
     ) v(player, score) join
     players p
     on v.player = p.player_id
order by p.group_id, v.score desc;

Here 是一个 dbfiddle。

【讨论】:

【参考方案5】:

使用row_number():

select group_id, player_id
from (
    select
        p.*,
        row_number() over(
            partition by p.group_id 
            order by case 
                when m.first_player = p.player_id then m.first_score 
                else m.second_score 
            end desc,
            player_id
        ) rn
    from players p
    inner join matches m
        on m.first_player = p.player_id or m.second_player = p.player_id
) x
where rn = 1

Demo on DB Fiddle

| group_id | player_id |
| -------- | --------- |
| 1        | 65        |
| 2        | 20        |

注意:第 3 组只有一名玩家(player_id 40),他们没有参加任何比赛。

【讨论】:

没有 row_number > 返回值:+---+----+ | 1 | 65 | | 2 | 20 | +---+----+ @yan:第 3 组只有一名玩家(player_id 40),他们没有参加任何比赛。

以上是关于如何使用 SQL 从每个组中获得最高得分球员?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 创建一个 NBA 得分图

如何从每组中获得前 1 行? (T-SQL)

蟒蛇统计分析

Oracle SQL:如何从组中查找记录

击球率最高的前 10 名球员

找到每个球员最长的连续得分