趣味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感兴趣的朋友可以下载下来玩玩。

发布了79 篇原创文章 · 获赞 322 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_15329947/article/details/97680660
今日推荐