点击上方“罗晓胜”,马上关注,您的支持对我帮助很大
上期文章
/ 前言 /
前面其实我们已经接触过子查询了,一句话解释,子查询就是将 上一次查询的结果 作为 本次查询的原始数据(或是查询条件)。
适用范围:当你的需求一次查询无法满足需求时(一次select找不到你要的数据,得多次查询),子查询所实现的功能,完全可以被多表联查代替,子查询能干的事,多表联查也能干。/ 正文 /
本章要点
• 子查询语法介绍
• 单行子查询
• 多行子查询
• 相关子查询
• EXISTS和NOT EXISTS操作符
子查询的基本语法
• 子查询的语法结构:SELECT 查询列 FROM 表名 WHERE 列名 操作符 (SELECT 查询列 FROM 表名);
• 括号内的查询叫做子查询(Subquery)或者内部查询(Inner Query),外面的查询叫做主查询(Main query)或外部查询 (Outer query)。
• 例 子查询当做条件示例
查询班级叫'一班'的所用用户
SELECT id, name, age, c_class
FROM student
WHERE c_class = (SELECT id FROM t_class WHERE name = '一班');
子查询注意事项
• 关于子查询,需要注意以下几点:– 子查询需要写在括号中;– 子查询需要写在运算符的右端;– 子查询可以写在WHERE,HAVING,FROM子句中;– 子查询中通常不写ORDER BY子句。
子查询的种类
单行子查询(单列) 子查询返回的记录有且只有一条 多行子查询(单列) 子查询返回记录的条数可以是一条或多条 多列子查询 多列数据比较
单行子查询
• 单行子查询,子查询返回的记录有且只有一条。单行子查询要 求使用单行操作符,即: – >大于 – >= 大于等于 – < 小于 – <= 小于等于 – =等于 – <> 不等于
WHERE子句中单行子查询
• 例 查询所有为一班的学生
SELECT id, name, age, c_class
FROM student
WHERE c_class = (SELECT id FROM student WHERE name = '一班');
HAVING子句中单行子查询
• 除了在WHERE子句中外,也可以在HAVING子句中书写子查询。
• 例 查询学生班级总数大于平均班级号的班级和班级数
SELECT c_class,COUNT(c_class)
FROM student
GROUP BY c_class
HAVING COUNT(c_class) > (SELECT AVG(id) FROM t_class GROUP BY id);
多行子查询
• 多行子查询,子查询返回记录的条数可以是一条或多条。多行 子查询需要使用多行操作符。常用的多行操作符包括:
– IN – ANY – ALL
IN、ANY、ALL的使用
• IN操作符和以前介绍的功能一致,判断是否与子查询的任意一 个返回值相同。返回的结果可以是一条或多条。
• 例 多行子查询示例——IN操作符。
SELECT a.id,a.name, a.age ,a.c_class
FROM student a
WHERE a.c_class IN (SELECT b.id FROM t_class b where b.id = 1 or b.id =2);
• ANY:表示任意的。
– < ANY 比子查询返回的任意一个结果小即可,即小于返回结 果的最大值。– = ANY 和子查询中任意一个结果相等即可,相当于IN。– > ANY比子查询返回的任意一个结果大即可,即大于返回结 果的最小值。
• ALL:表示所有的。
– < ALL 比子查询返回的所有的结果都小,即小于返回结果的 最小值。– > ALL比子查询返回的所有的结果都大,即大于返回结果的 最大值。– = ALL 无意义,逻辑上也不成立。
• 例 ANY操作符。
SELECT a.id,a.name, a.age,a.c_class
FROM student a
WHERE a.c_class > ANY (SELECT b.id FROM t_class b where b.id = 1 or b.id =2);
• 例 ALL操作符。
SELECT a.id,a.name, a.age ,a.c_class
FROM student a
WHERE a.c_class > ALL (SELECT b.id FROM t_class b where b.id = 1 or b.id =2);
多列子查询
显示名称和班级与班级表同名的用户
SELECT a.id,a.name, a.age ,a.c_class
FROM student a
WHERE (name, c_class) IN (SELECT name, id FROM t_class ) ;
子查询中空值问题
• 例7-14 子查询空值示例。
SELECT a.id,a.name, a.age ,a.c_class
FROM student a
WHERE a.c_class NOT IN (SELECT b.id FROM t_class b);
返回结果:未选定行
• 出现这种情况的原因有两个:– 子查询中返回值中包含有空值;– NOT IN操作符对空值不忽略。
• NOT IN操作符相当于<> ALL,即除了列表值的所有值,就包括了 空值NULL,结果即为空。
FROM语句中子查询
• 例 用子查询当做连接查询的另一张表
SELECT a.id,a.name, a.age ,a.c_class
FROM student a , (SELECT id,name FROM t_class GROUP BY id) t
WHERE a.c_class = t.id ;
相关子查询
不相关子查询:一条Sql语句中含有多条SELECT语句,先执行子查询,再执行外查询,子查询可对立运行
关键字:(1)先子查询,再外查询 2)可以对立运行,即可以单独运行子查询,对外查询不干扰
相关子查询:子查询不能独立运行,并且先运行外查询,再运行子查询
关键字:(1)先外查询,再子查询 2)子查询不能独立运行
当子查询从一个在父查询涉及的表中引用一个列时,执行相关子查询。对于由父查询处理的每一行相关子查询都执行一次。相关子查询被用于 row-by-row 处理。对父查询的每一行,每个子查 询被执行一次
• 相关子查询中,内部查询需引用外部查询的列,进行交互判断。相关子查询的执行方式是一行行操作。外部查询每执行一行操 作,内部查询都要执行一次。
• 例 每个班级高于平均的用户信息, (也可通过分组判断实现)。
SELECT a.id,a.name, a.age ,a.c_class ,a.c_score
FROM student a
WHERE a.c_score >(SELECT AVG(b.c_score) FROM student b WHERE b.c_class = a.c_class);
EXISTS和NOT EXISTS操作符
• 相关子查询还可使用EXISTS和NOT EXISTS操作符。
• EXISTS判断存在与否。具体操作如下:
– 子查询中如果有记录找到,子查询语句不会继续执行,返回 值为TRUE;
– 子查询中如果到表的末尾也没有记录找到,返回值为FALSE。
• EXISTS子查询并没有确切记录返回,只判断是否有记录。而且 只要找到相关记录,子查询就不需要再执行,然后再进行下面 的操作。这样大大提高了语句的执行效率。
• NOT EXISTS正好相反,判断子查询是否没有返回值。如果没 有返回值,表达式为真,如果找到一条返回值,则为假。
• 例 查询用户表的班级ID 存在于班级表中的数据。
SELECT a.id,a.name, a.age ,a.c_class ,a.c_score
FROM student a
WHERE EXISTS (SELECT 1 FROM student b WHERE b.c_class = a.c_class);
• 因为EXISTS子句中,并没有确切记录返回,只返回真或假。所 以’1’只是占位用,无实际意义。
• 例 查询用户表的班级ID 不存在于班级表中的数据。
SELECT a.id,a.name, a.age ,a.c_class ,a.c_score
FROM student a
WHERE NOT EXISTS (SELECT 1 FROM student b WHERE b.c_class = a.c_class);
• NOT EXISTS操作符因为运算方法与NOT IN不同,只会返回 TRUE或FALSE,不会返回空值,所以不需要考虑子查询去除 空值的问题。
往期推荐:





