趣味MySQL:查询NBA球员的冠军总数
1. Kobe or Lebron?
写这篇博客的目的完全来自于一位朋友在我朋友圈的评论,他半开玩笑地说,你试试用SQL查出科比和勒布朗的夺冠总数。我是一个资深NBA球迷,同时也是科蜜(科比.布莱恩特的球迷),所以我觉得用我的职业技术之一SQL来做这个“玩笑”式的需求,非常有趣。
2. 建表
前言:建表的规范
以下规范均引用自《阿里巴巴 Java开发手册 v1.4.0》
2.1 创建表、字段和索引
咱们可以创建一个数据库叫nba。
建立一张表叫player,里面有球员ID pid(int)作为主键,球员姓名name(varchar),场上位置position(varchar)等字段。
然后再建立一张表叫team,主要包括球队ID tid(int),队名name(varchar),所在城市city(varchar)等;由于同城不能有重名的球队,所以可以对name和city两个字段建立唯一索引city_name。
由于player和team是多对多关系,所以我们肯定需要建立一张中间表叫player_team,主要包括主键ptid(int),球员pid(int), 球队tid(int)以及年份year(int),这种中间表可以展示哪一年哪位球员在哪只球队;所以对于pid, tid, year三个字段可以建立唯一索引。
fk_pid和fk_tid是后面要建立的外键,也会被默认添加普通索引。
最后我们需要建立一张表叫夺冠表champion,这个表可以不用主键,包括年份year(唯一索引, int),球队team(int,对应球队tid),总决赛fmvp(int,对应球员pid)三个字段。
同理,fk_fmvp_pid和fk_team_tid是后面要建立的外键,也会被默认添加普通索引。
2.2 创建外键
上述工作做完后,需要根据表之间的一对多关系添加外键。
如图,建立外键如下:
在champion表上分别建立与player和team表的外键fk_fmvp_pid和fk_team_tid:
在player_team表上分别建立与player和team表的外键fk_pid和fk_tid:
外键添加完后,在SQLyog的架构设计器中显示各表之间的关系如下:
3. 插入数据
咱们可以根据自己对NBA球星的喜好来插入数据,但是请注意插入的数据要对最终的查询结果有一定的干扰性;在干扰数据下仍能查出正确结果,可以确保SQL的严谨性。比如,可以在中间表player_team插入科比和勒布朗没有夺冠的年份所在的球队:2006,2007年pid为1的球员科比在tid为1的球队湖人队,2009,2010年pid为2的球员勒布朗在tid为4的球队骑士队。还可以在champion表中插入干扰数据:2000 ~ 2002年fmvp(pid)为4的球员奥尼尔在team(tid)为1的球队湖人队夺冠并拿下FMVP。
4. SQL查询
4.1 查询夺冠情况
我们可以先不急着查出科比和勒布朗各自的冠军数量,而是可以看看他们分别在哪一年夺冠,那一年的夺冠球队和FMVP,这样心里先有个底:
SELECT c.year, kl.pid, kl.player_name, kl.team_name, p2.name fmvp
FROM champion c INNER JOIN
(SELECT p.pid, p.name player_name, pt.year, t.tid, t.name team_name
FROM player p
INNER JOIN player_team pt
ON p.pid = pt.pid
INNER JOIN team t
ON pt.tid = t.tid
WHERE p.name = 'Kobe Bryant' OR p.name = 'Lebron James') kl
INNER JOIN player p2
ON c.year = kl.year AND c.team = kl.tid AND c.fmvp = p2.pid
order by c.year;
查询结果如下:
查询结果完全正确!
4.2 查询夺冠数量
吃了这颗定心丸,接着,咱们可以直接查询两人的夺冠数了:
SELECT kl.player_name player, COUNT(*) champions
FROM champion c INNER JOIN
(SELECT p.pid, p.name player_name, pt.year, t.tid
FROM player p
INNER JOIN player_team pt
ON p.pid = pt.pid
INNER JOIN team t
ON pt.tid = t.tid
WHERE p.name = 'Kobe Bryant' OR p.name = 'Lebron James') kl
ON c.year = kl.year AND c.team = kl.tid
GROUP BY kl.pid, kl.player_name;
查询结果如下,完全正确:
4.3 彩蛋
阿伦.艾弗森是除了科比之外我最欣赏的后卫之一,在节奏缓慢,空间拥挤的21世纪初期他便能四夺得分王,如果AI能来到当今这个快节奏,体毛哨的时代,再给予绝对球权,他能否成为场均40+的高效得分机器?
SELECT p.name, p.position, CONCAT(t.city, ' ', t.name) team FROM player p
INNER JOIN player_team pt ON p.pid = pt.pid
INNER JOIN team t ON pt.tid = t.tid
WHERE p.name = 'Allen Iverson';
5. 源码下载
本文相关SQL已上传至我的码云,点进nba文件夹即可;对NBA和SQL感兴趣的朋友可以下载下来玩玩。
推荐阅读