子查询
子查询就是嵌套在查询中的查询, 目的是为了进行更复杂的查询, 同时可以理解查询的过程.
子查询也分为两种, 一种是关联子查询, 一种是非关联子查询.
关联子查询与非关联子查询
子查询的划分是依据了子查询是否执行多次来进行划分的.
子查询从数据表中查询数据结果, 如果这个数据结果只执行一次, 之后这个数据结果作为主查询的条件进行执行, 这种就是非关联子查询.
同样, 如果子查询需要执行多次, 即采用循环的方式, 先从外部查询开始, 每次传入子查询进行查询, 之后结果反馈给外部, 这种嵌套方式就是关联子查询.
举个例子, 创建五张表, player表是球员表, team表是球队表, team_score
是球队比赛成绩表, player_score
是球员比赛成绩表, height_grades
是球员身高对应的等级表.
如果仅仅学习的话可以自己创建表, 看完之后自己出题自己来做, 没必要非要上面的表, 如需下载请到 https://github.com/cystanford/sql_nba_data 去下载.
SELECT player_name, height FROM player WHERE height = (SELECT max(height) FROM player); // 查询身高最高的球员信息
上面的子查询就是非关联子查询, 查询最高身高的子查询仅仅执行了一次, 不依赖于外部查询.
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); // 查询每个球队中大于平均身高的球员信息
这个子查询就是关联子查询了, 因为里面的查询球队队员平均身高依赖于外(主)查询, 需要使用主查询来获取当前队员是哪个球队的.
EXISTS子查询
关联子查询通常也和EXISTS一起使用, EXISTS子查询用来判断条件是否满足, 满足的话为TRUE, 不满足的话为FALSE. 现在想查询出场过的球员有哪些, 这个就需要到player_score中去查询全部的球员Id, 有记录表示出场过.
SELECT player_id, team_id, player_name FROM player WHERE EXISTS (SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id); // EXISTS的关联条件是写在子查询中的
有EXISTS, 自查就有NOT EXISTS, 也就是不存在, 与EXISTS是完全相反的结果.
与EXISTS有相同含义的还有IN, 这个下面说.
集合比较子查询
集合比较子查询的作用是与另一个查询结果集进行比较, 可以再子查询中使用IN, ANY, ALL和SOME操作符.
现在想查询出场过的球员有哪些, 可以这样写:
SELECT player_id, team_id, player_name FROM player WHERE player_id in (SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id); // in查询出场过的球员
哪种效率更好取决于查询表于关联表的数据大小, 查询表达, IN的效率高, 相反, EXISTS的效率高.
接下来说说ANY和ALL, 这两个通常需要使用比较符, 比较符包括了(>)(=)(<)(>=)(<=)(<>)等.
要查询比印第安纳步行者(对应的twam_id是1002)中任何一个球员身高高的球员信息, sql如下
SELECT player_id, player_name, height FROM player WHERE height > ANY (SELECT height FROM player WHERE team_id = 1002); // 主要身高高于子查询中的人一个一个就可以
SQL: SELECT player_id, player_name, height FROM player WHERE height > ALL (SELECT height FROM player WHERE team_id = 1002); // 身高高于球员中的任意一个球员的身高, 简单的说就是比球队中身高最高的球员还要高.
SELECT p1.* FROM player p1 WHERE p1.height = (SELECT MAX(height) FROM player p2 WHERE p1.team_id = p2.team_id); // 查询每支球队中, 身高最高的球员信息
ANY和ALL关键字必须与一个比较操作符在一起使用, 不适用起不到集合比较的作用, ANY和ALL就没有任何意义.
子查询作为计算字段
想查询每支球员的球员数
SELECT team_name, (SELECT count(*) FROM player WHERE player.team_id = team.team_id) AS player_num FROM team;