sql多表条件查询_sql面试题:多表查询

3a2a4562dd0e93f7f690ef80bc7b0f91.png

复仇者联盟中多个人物之间有着关系,同样的,表和表之间也会有关系,这种关系在数据库里叫做联结(join),多表查找也是通过联结来实现的。

这是《从零学会sql》系列课程第5节课《多表查询》的练习题,也是常考常考的面试题。

f04ba41430316d7bb09b1dbb3d15a313.png

题目来自sqlzoo的多表查询题目。网址:

https://sqlzoo.net/wiki/The_JOIN_operation/zh

这部分题目使用的是‘2012年欧洲足球锦标赛’数据库里的表。

dd26a0fe21c67b91ddc8de8c6a4bdc0c.png

1.比赛信息表game

id比赛编号,mdate比赛日期, stadium比赛地点, team1对战双方(球队编号1), team2对战双方(球队编号2)

0be6b668c9dd108dbbd512708830e4eb.png

2.进球信息表goal

matchid比赛编号,teamid球队编号, player进球球员的姓名,gtime多长时间进的球(从开始比赛到进球多长时间,单位:分钟)

f1b8677e83faee80f7a35bfbc2d4e6be.png

比赛信息表game(id比赛编号)和进球信息表goal(matchid比赛编号)通过‘比赛编号’联结

3.球队信息表eteam 

id球队编号(联结2) teamname 球队名称 coach教练

caf8b688879851355b09f16beae48ff4.png

进球信息表goal(teamid球队编号)球队信息表eteam(球队编号id)通过‘球队编号’联结

如何做题?

7f12a0b0296e01c67f972ef39f6eae58.png

练习题答案

先自己在sqlzoo平台里(网址:

https://sqlzoo.net/wiki/The_JOIN_operation/zh)

输入sql,查看运行结果,然后再和下面的答案对比哪里写的不一样

1. 在进球表(goal)中查找德国球队(teamid = 'GER')进球的比赛编号(matchid),进球球员姓名(player)

select matchid, player from goal where teamid = 'GER';

2. 在比赛信息表(game)查找比赛编号1012的信息

select id,stadium,team1,team2from game where id = 1012;

3. 查找德国队进球球员姓名,球队编号(在进球信息表goal), 比赛地点,比赛日期(在比赛信息表game)

问题分析:

进球球员姓名,球队编号(在进球信息表goal)

比赛地点,比赛日期(在比赛信息表game)

两个表如何联结?通过比赛编号

哪一种联结?需要两个表中共同部分,内联结

select b.player, b.teamid, a.stadium, a.mdatefrom game as a inner join goal as b on a.id=b.matchidwhere b.teamid = 'GER';

4. 查找姓名中以Mario开头的进球球员,符合条件球员参加比赛的对战双方

问题分析:

1)查找出进球球员姓名(进球信息表goal:进球球员姓名player),

比赛的对战双方(比赛信息表game:对战双方team1,team2)

两个表如何联结?通过比赛编号

哪一种联结?需要两个表中共同部分,内联结

2)加入条件:进球球员姓名中以Mario开头,模糊查询:like 'Mario%'

select a.team1, a.team2, b.playerfrom game as a inner join goal as b on a.id=b.matchidwhere b.player like 'Mario%';

5. 查找进球球员的姓名、球队编号、教练、多长时间进球。要求多长时间进球<=10分钟

问题分析:

1)查找出进球球员的姓名、球队编号、多长时间进球(在进球信息表goal)

教练(在球队信息表eteam)

两个表如何联结?通过球队编号(进球信息表goal:teamid球队编码 = 球队信息表eteam:id球队编码)

哪一种联结?需要两个表中共同部分,内联结

2)加入条件:多长时间进球<=10分钟

select b.player, b.teamid, c.coach, b.gtimefrom goal as b inner join eteam as c on b.teamid=c.idwhere b.gtime<=10;

6. 'Fernando Santos'作为教练的比赛日期,球队编号有哪些?

问题分析:

1)查找出

教练(在球队信息表eteam)

比赛日期,球队编码(在比赛信息表game)

两个表如何联结?通过球队编号(比赛信息表game:team1对战双方的球队编码(team1或者team2的球队编码) = 球队信息表eteam:id球队编码)

哪一种联结?需要两个表中共同部分,内联结

2)加入条件:教练是'Fernando Santos'

select a.mdate, c.teamnamefrom  game as a inner join eteam as c on a.team1=c.idwhere c.coach = 'Fernando Santos';

7. 在比赛地点'National Stadium, Warsaw'有哪些进球球员?

问题分析:

1)查找

比赛地点(在比赛信息表game),进球球员(在进球信息表goal)

2)加入条件:比赛地点是'National Stadium, Warsaw'

select b.playerfrom game as a inner join goal as b on a.id=b.matchidwhere a.stadium = 'National Stadium, Warsaw';

8.射入德国球门的球员姓名

问题分析:

1)查找进球球员姓名,对战双方

2)条件:有一个球队是德国(球队编号'GER'),被射入了球

select distinct b.playerfrom game as a inner join goal as b on a.id = b.matchidwhere (b.teamid = a.team1 and a.team2 = 'GER') or (b.teamid = a.team2 and a.team1 = 'GER');

1)解释下where子句中的条件:

主队是德国或者客队是德国,比如

德国 和 A对比赛(德国是主队),进球的是A队

A队和德国比赛(德国是客队),进球的是A队

所以条件是(b.teamid = a.team1 and a.team2 = 'GER') or (b.teamid = a.team2 and a.team1 = 'GER')

2)内联结的结果中入门球员有重复值,用distinct去掉重复值

9. 查找出球队名称,和每个球队进球人数

问题分析:

球队名称(球队信息表eteam),和每个球队进球人数(进球信息表goal:按球队编号分组统计count(teamid))

select c.teamname, count(b.teamid)from eteam as c inner join goal as b on c.id=b.teamidgroup by b.teamid;

上面这么写是不对的,因为查下结果中要查出球队名称(teamname)。如果按球队编码(teamid)来分组,结果中没法显示球队名称。所以这里我们用球队名称(teamname)来分组。正确的sql是:

select c.teamname, count(c.teamname)from eteam as c inner join goal as b on c.id=b.teamidgroup by c.teamname,;

10. 查找出所有比赛地点,每个比赛地点的进球数

问题分析:

比赛地点(比赛信息表game),和每个比赛地点的进球数(进球信息表goal:按比赛地点分组,对进球人员进行汇总count(player))

联结方式是什么?要查出比赛信息表game中全部比赛地点,所以是左联结

select a.stadium, count(b.player)from game as a left join goal as b on a.id=b.matchidgroup by a.stadium;

11. 查找出有波兰球队'POL'参加的比赛编号,比赛日期,对应这场比赛的进球数

select a.id,a.mdate, count(b.player)from game as a inner join goal as b on a.id = b.matchid where (team1 = 'POL' OR team2 = 'POL')group by a.id;

上面sql运行后会报错,是因为分组结果中没有比赛日期(mdate),而查询结果要求有比赛日期(mdate)。

为了让查询结果中有比赛日期(mdate),我们在分组group by子句中再加上分组比赛日期(mdate)。

这时候group by a.id,a.mdate 有两个分组列,表示这两个列的值都相同时才算一组。因为比赛编号(id),比赛日期(mdate)都是一对一的,不会改变之前的分组结果,但有可以让查询结果中有分组中的列。正确的sql:

select a.id,a.mdate, count(b.player)from game as a inner join goal as b on a.id = b.matchid where (team1 = 'POL' or team2 = 'POL')group by a.id,a.mdate;

12. 对于德国队'GER'得分的每场比赛,显示比赛编号,比赛日期和'GER'得分的进球数

问题分析:

比赛编号,比赛日期(在比赛信息表game)和'GER'得分的进球数(进球信息表goal:按比赛地点分组,对进球人员进行汇总count(player))

select a.id,a.mdate,count(player) from game as a inner join goal as b on a.id=b.matchid where b.teamid='GER' group by a.id,a.mdate;

13. 查找出所有比赛的日期,每场比赛中对战双方各自的进球数(也就是team1进球数,team2进球数)

问题分析:

当比赛信息表game中的球队编号(team1)也出现在进球信息表(goal)中时,表示这个球队进球了,使用case语句来统计

select a.mdate,a.team1,sum(case when a.team1=b.teamid then 1 else 0 end) as score1,a.team2,sum(case when a.team2=b.teamid then 1 else 0 end) score2 from game as a left join goal as b on a.id = b.matchidgroup by a.id,a.mdate,a.team1,a.team2;

推荐:如何用最短的时间找到初级数据分析师工作?

59d8773a5df5240048c32b1a7ef8759d.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值