订阅更新

球队积分:主客场两种身份都要算

SQL 实战 123 题 · 第 81 题 中等 约 3 分钟读完

LeetCode 1212 · 条件求和、OR 关联、零值保留

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

我会先把每场比赛展开成主队一行、客队一行,各自按胜平负算出 3/1/0 分,UNION ALL 后用球队表 LEFT JOIN 汇总,IFNULL 补 0,按积分降序、ID 升序排序。展开后每行只表达一支球队的一场比赛,比在一条 SUM 里写四个 IF 更不容易错。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

题意

球队表和比赛表(主队、客队、双方进球)。赢一场 3 分、平 1 分、输 0 分。算出每支球队的总积分,按积分降序、积分相同按球队 ID 升序;没参赛的球队积分为 0。

表结构

  • Teams:team_id(主键)、team_name
  • Matches:match_id(主键)、host_team、guest_team、host_goals、guest_goals

思路

一支球队可能是主队也可能是客队,用球队表 LEFT JOIN 比赛表、条件写成「是主队或是客队」,就拿到了它参加的所有比赛。再用 CASE 按它在这场是主还是客、比分如何算出得分,按球队汇总。LEFT JOIN 保证没比赛的球队也在,积分用 IFNULL 补 0。

参考解法

select team_id , team_name ,sum(
if(team_id = host_team && host_goals>guest_goals ,3,0)+
if(team_id = host_team && host_goals=guest_goals,1,0)+
if(team_id = guest_team && host_goals=guest_goals,1,0)+
if(team_id = guest_team && host_goals<guest_goals ,3,0)
)num_points
from Teams t left join Matches m
on t.team_id =m.host_team  or t.team_id =m.guest_team  
group by team_id ,team_name
order by num_points desc,team_id

另一种写法:先把每场比赛展开成两支球队各一行,再汇总

SELECT t.team_id, t.team_name, IFNULL(SUM(s.pts), 0) AS num_points
FROM Teams t
LEFT JOIN (
  SELECT host_team AS team, CASE WHEN host_goals > guest_goals THEN 3 WHEN host_goals = guest_goals THEN 1 ELSE 0 END AS pts FROM Matches
  UNION ALL
  SELECT guest_team, CASE WHEN guest_goals > host_goals THEN 3 WHEN host_goals = guest_goals THEN 1 ELSE 0 END FROM Matches
) s ON t.team_id = s.team
GROUP BY t.team_id, t.team_name
ORDER BY num_points DESC, t.team_id

易错点

  • 只关联主队或只关联客队,会漏掉一半比赛。
  • 没参赛的球队 SUM 结果是 NULL,要补 0。
  • 也可以先把比赛展开成「每队每场一行」再汇总,逻辑更清楚。
刷题进度保存在当前浏览器