mač*_*ček 4 mysql join ranking dense-rank greatest-n-per-group
我有两个表players和scores.
我想生成一个类似于下面的报告:
player first score points
foo 2010-05-20 19
bar 2010-04-15 29
baz 2010-02-04 13
Run Code Online (Sandbox Code Playgroud)
现在,我的查询看起来像这样:
select p.name player,
min(s.date) first_score,
s.points points
from players p
join scores s on s.player_id = p.id
group by p.name, s.points
Run Code Online (Sandbox Code Playgroud)
我需要s.points与min(s.date)返回的行相关联的那个.这个查询会发生这种情况吗?也就是说,我怎么能确定我正在s.points为连接的行获得正确的值?
旁注:我认为这与MySQL缺乏密集排名有某种关系.这里最好的解决方法是什么?
这是Stack Overflow上经常出现的最大n组问题.
这是我通常的答案:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and s2.date < s.date
where
s2.player_id is null
;
Run Code Online (Sandbox Code Playgroud)
换句话说,给定得分s,尝试找到同一玩家的得分s2,但具有更早的日期.如果没有找到早期分数,那么s是最早的分数.
关于关系的评论:你必须有一个政策,以便在平局的情况下使用哪一个.一种可能性是如果使用自动递增主键,则值最小的主键是较早的主键.请参阅下面的外部联接中的附加术语:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and (s2.date < s.date or s2.date = s.date and s2.id < s.id)
where
s2.player_id is null
;
Run Code Online (Sandbox Code Playgroud)
基本上你需要添加决胜局术语,直到你找到一个保证唯一的列,至少对于给定的玩家来说.表的主键通常是最好的解决方案,但我已经看到了另一列适合的情况.
关于我与@OMG Ponies分享的评论,请记住这种类型的查询从正确的索引中获益匪浅.