6-SQL子查询
(1) 什么是关联子查询,什么是非关联子查询 (嵌套查询)
子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件进行执行,那么这样的子查询叫做非关联子查询。
如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后再将结果反馈给外部,这种嵌套的执行方式就称为关联子查询。
哪个球员的身高最高,最高身高是多少,就可以采用子查询的方式:
-- 非关联子查询示例
select player_name, height FROM player where height = (select max(height) from player);
首先通过select max(height) from player 得到最高身高这个数值,然后再将这个值在player表中匹配查找,看谁符合这个值,进行输出。
查询每个球队中大于平均身高的球员有哪些,并显示他们的球员姓名、身高以及所在球队 ID。
-- 关联子查询示例
select player_name, height, team_id from player as a where height > (select avg(height) from player as b where a.team_id = b.team_id);
如果子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重新计算一次,这样的子查询就称之为关联子查询
(2) EXISTS子查询
想要看出场过的球员都有哪些,并且显示他们的姓名、球员 ID 和球队 ID。在这个统计中,是否出场是通过 player_score 这张表中的球员出场表现来统计的,如果某个球员在 player_score 中有出场记录则代表他出场过,这里就使用到了 EXISTS 子查询,
select player_name, player_id, team_id from player where exists (select player_id from player_score where player.player_id = player_score.player_id);
查询球员不存在于player_score表中的数据
select player_name, player_id, team_id from player where not exists (select player_id from player_score where player.play_id = player_score.player_id);
(3) 集合比较子查询-- 与另一个查询结果集进行比较
主要查询操作符及定义:
IN 判断是否在集合中
ANY 需要与操作符一起使用,与子查询返回的任何值做比较
ALL 需要与操作符一起使用,与子查询返回的所有值做比较
SOME 实际上是ANY的别名,作用相同,一般尝试用ANY
想要看出场过的球员都有哪些,并且显示他们的姓名、球员 ID 和球队 ID。
select player_name, player_id, team_id from player where player_id in (select player_id from player_score where player.player_id = player_score.player_id);
不难看出,IN操作符和EXISTS操作符的查询结果是一致的,那么应该如何选择IN和EXISTS?
SELECT * FROM A WHERE cc IN (SELECT cc FROM B)
SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc)
实际上在查询过程中,在我们对 cc 列建立索引的情况下,我们还需要判断表 A 和表 B 的大小。在这里例子当中,表 A 指的是 player 表,表 B 指的是 player_score 表。如果表 A 比表 B 大,那么 IN 子查询的效率要比 EXIST 子查询效率高,因为这时 B 表中如果对 cc 列进行了索引,那么 IN 子查询的效率就会比较高。同样,如果表 A 比表 B 小,那么使用 EXISTS 子查询效率会更高,因为我们可以使用到 A 表中对 cc 列的索引,而不用从 B 中进行 cc 列的查询。
ANY 和 ALL 都需要使用比较符,比较符包括了(>)(=)(<)(>=)(<=)和(<>)等。
查询球员表中,比印第安纳步行者(对应的 team_id 为 1002)中任何一个球员身高高的球员的信息,并且输出他们的球员 ID、球员姓名和球员身高
select player_name, player_id, team_id, height from player where height > any (select height from player where team_id = 1002);
查询比印第安纳步行者(对应的 team_id 为 1002)中所有球员身高都高的球员的信息,并且输出球员 ID、球员姓名和球员身高
select team_id, player_id, player_name, height from player where height > all (select height from player where team_id = 1002);
请注意:ANY、ALL 关键字必须与一个比较操作符一起使用。因为如果你不使用比较操作符,就起不到集合比较的作用,那么使用 ANY 和 ALL 就没有任何意义
(4) 将子查询作为计算字段
实际上子查询也可以作为主查询的计算字段。
查询每个球队的球员数,也就是对应 team 这张表,我需要查询相同的 team_id 在 player 这张表中所有的球员数量是多少。
select team_name, (select count(*) from player where player.team_id = team.team_id) as player_num from team;
在 player 表中只有底特律活塞和印第安纳步行者的球员数据,所以它们的 player_num 不为 0,而亚特兰大老鹰的 player_num 等于 0。在查询的时候,我将子查询SELECT count(*) FROM player WHERE player.team_id = team.team_id作为了计算字段,通常我们需要给这个计算字段起一个别名,这里我用的是 player_num,因为子查询的语句比较长,使用别名更容易理解。
查询得到场均得分大于 20 的球员。场均得分从 player_score 表中获取,同时你需要输出球员的 ID、球员姓名以及所在球队的 ID 信息
-- 使用IN
select team_id, player_id, player_name from player where player_id in (select player_id from player_score GROUP BY player_id HAVING(avg(score) > 20));
-- 使用EXISTS
select team_id, player_id, player_name from player where exists (select player_id from player_score GROUP BY player_id HAVING(avg(score) > 20) and player.player_id = player_score.player_id);
select team_id, player_id, player_name from player where exists (select player_id from player_score where player.player_id = player_score.player_id GROUP BY player_id HAVING avg(score) > 20);
-- 使用JOIN
SELECT
t2.player_id,
t2.player_name,
t2.team_id,
t3.v
FROM
player AS t2
JOIN (
SELECT
t1.player_id,
avg( t1.total ) AS v
FROM
(
SELECT
player_id,
sum( score ) AS total
FROM
player_score
WHERE
game_id IN ( SELECT game_id FROM player_score GROUP BY game_id )
GROUP BY
player_id #对球员分组,计算在每场比赛中的总分数
) AS t1
GROUP BY
t1.player_id #对球员分组,计算所参加比赛的平均数
HAVING
v > 20 #场均得分大于20
) AS t3 ON t2.player_id = t3.player_id;
1、我理解的场均得分大于20,第一场得了40分,第二场得了2分,场均为21分满足条件
2、一场比赛中,球员可以出现多次
解析思路,先得出球员在每场比赛中的总分数,然后对球员分组,计算球员在所参加比赛中的平均数