【问题标题】:Query to get the best scorer per game查询以获得每场比赛的最佳得分手
【发布时间】:2021-03-06 19:38:20
【问题描述】:

我需要计算每个game_id 的最佳得分手(player_id / player_name)。正如你在下面看到的,我有三种情况:

  • 两个或更多人的进球数相同:在这种情况下,我们没有任何得分手。
  • 一个人是唯一的进球者。
  • 我们有一位得分明显最高的得分手。

我曾尝试查询每场比赛最佳得分手的game_idplayer_nameplayer_id,但没有成功。这是我的查询:

select j.id as game_id,jg.id as player_id, jg.nome s player_name,
       count(g.id) as numberOfGoals,
       RANK() OVER(PARTITION BY j.id  ORDER BY count(g.id) ) as rank 
from jogo j
inner join jogo_jogador jj on jj.jogo_id = j.id
inner join golo g on g.jogo_jogador_id = jj.id
inner join equipa_jogador ej on ej.id = jj.equipa_jogador_id
inner join jogador jg on jg.id = ej.jogador_id
group by jg.id, jg.nome, j.id
order by j.id, jg.nome, jg.id;

这是我目前得到的:

insert into tbl(game_id player_id   player_name numberofgoals   rank) 
values 
(1 , 1 ,'Marco Costa'    ,1  ,1), 
(1 , 4 ,'Olivier Marques',1  ,1), 
(2 , 1 ,'Marco Costa'    ,1  ,1), 
(3 , 9 ,'Ilidio Vatuva'  ,2  ,2), 
(3 ,10 ,'Joaquim Barros' ,1  ,1),
(4 ,11 ,'Diogo Mendonça' ,2  ,4), 
(4 ,10 ,'Joaquim Barros' ,1  ,1), 
(4 ,14 ,'John Smith'     ,1  ,1), 
(4 ,12 ,'Mário Jorge'    ,1  ,1), 
(5 , 7 ,'Ricardo Pereira',1  ,1), 
(6 , 8 ,'Danilo Barbosa' ,1  ,1), 
(6 , 9 ,'Ilidio Vatuva'  ,1  ,1), 
(6 ,19 ,'Micael Pereira' ,1  ,1), 
(6 ,18 ,'Ricardo Bateiro',2  ,4),
(7 , 8 ,'Danilo Barbosa' ,3  ,1), 
(9 , 8 ,'Danilo Barbosa' ,1  ,1),
(9 , 2 ,'Joao Azevedo'   ,1  ,1),
(9 , 7 ,'Ricardo Pereira',1  ,1), 
(10, 9 ,'Ilidio Vatuva'  ,1  ,1), 
(11, 3 ,'Kevin Soares'   ,1  ,1), 
(11, 1 ,'Marco Costa'    ,1  ,1),
(11,18 ,'Ricardo Bateiro',2  ,3), 
(12,21 ,'Daniel Silva'   ,1  ,1), 
(12, 9 ,'Ilidio Vatuva'  ,1  ,1), 
(13, 2 ,'Joao Azevedo'   ,1  ,1);

我正在使用 PostgreSQL 13.2。

对于game_id 1(例如):

  • 如果我无限制地运行子查询,我会得到两个可能的获胜者,目标数相同 (1)。在那种情况下,我们没有得分手。我们不选择任何人。
  • 如果我使用 Limit 运行子查询,它会选择一个玩家。

【问题讨论】:

    标签: sql postgresql select greatest-n-per-group window-functions


    【解决方案1】:

    每个 game_id 的最佳得分手(player_id/player_name)。

    四肢走动,这可能会做到:

    SELECT j.id AS game_id
         , x.player_id
         , jg.nome AS player_name
         , x.number_of_goals
    FROM   jogo j
    JOIN   LATERAL (
       SELECT jj.id AS player_id 
            , count(*) AS number_of_goals
            , lag(count(*)) OVER (ORDER BY count(*) DESC) AS next_best  -- descending!
       FROM   jogo_jogador   jj
       JOIN   golo            g ON g.jogo_jogador_id = jj.id
       WHERE  jj.jogo_id = j.id
       GROUP  BY jj.id
       ORDER  BY count(*) DESC, next_best DESC NULLS LAST
       LIMIT  1
       ) x ON x.number_of_goals > x.next_best  -- better than the next best
           OR x.next_best IS NULL              -- or there was no next best
    JOIN   jogador jg ON jg.id = x.player_id;
    

    LATERAL 子查询 x 我计算每个球员的进球数,按降序排列球员 (DESC !) 并选择得分最高的球员 - 如果它比下一个更好(或者没有次佳)。

    next_best 是使用窗口函数lag() 确定的,基于相同的降序。

    关于DESC NULLS LAST

    之后仅检索实际获胜者的玩家姓名。

    在不知道你的关系设计的情况下,我假设 jogo_jogador.id 实际上是玩家 ID (jogador.id),根本不需要加入 equipa_jogador

    使用稍快的count(*)(而不是count(g.id)),因为我们可以。

    【讨论】:

    • 感谢您的帮助。我用您的解决方案更新了我的问题。它适用于所有情况,除了我们在同一场比赛中进球数相同的情况。对于game_id 1,没有得分手,选择“player_id”1。
    • @Jcbo:为什么要从我的查询中删除(需要的)LIMIT 1?取消注释,加入条件 ON x.number_of_goals > x.next_best 应该删除并列的获胜者。
    • 是的!请参阅更新的问题。谢谢
    • @Jcbo:啊,我明白了。我们需要第二个 ORDER BY 表达式 next_best DESC NULLS LAST 来找出极端情况。
    猜你喜欢
    • 2015-11-02
    • 2015-03-11
    • 2019-08-26
    • 2021-11-17
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多