SQL 子查询进阶
学习 EXISTS/ANY/ALL 子查询 · 难度:高级 · +15XP
SQL 子查询进阶
子查询(Subquery)是嵌套在另一个 SQL 语句内部的 SELECT 查询。基础子查询通常放在 WHERE 子句中用于比较,而进阶子查询则涵盖了更多的使用场景和特殊操作符,如 EXISTS、ANY、ALL 等,使你能够表达更复杂的业务逻辑,例如"查询那些至少有一门课程成绩大于 90 的学生"或"找出比所有一年级学生分数都高的学生"。
子查询的分类
| 分类 | 位置 | 返回值 | 示例 |
|---|---|---|---|
| 标量子查询 | SELECT/WHERE | 单个值 | WHERE score > (SELECT AVG(score)...) |
| 行子查询 | WHERE | 单行 | WHERE (a,b) = (SELECT ...) |
| 列子查询 | WHERE IN | 多行单列 | WHERE id IN (SELECT ...) |
| 表子查询 | FROM | 多行多列 | FROM (SELECT ...) AS t |
EXISTS 子查询
EXISTS 用于检查子查询是否返回至少一行数据,返回布尔值(TRUE/FALSE)。它通常用于关联子查询:
-- 查询至少有一门课程成绩的学生
SELECT name FROM students s
WHERE EXISTS (
SELECT 1 FROM scores sc WHERE sc.student_id = s.id
);
-- NOT EXISTS:查询没有任何课程的学生
SELECT name FROM students s
WHERE NOT EXISTS (
SELECT 1 FROM scores sc WHERE sc.student_id = s.id
);
-- 查询分数高于所有一年级学生的高年级学生
SELECT name, score FROM students s
WHERE grade > 1 AND score > ALL (
SELECT score FROM students WHERE grade = 1
);
ANY / ALL 操作符
-- ANY: 大于子查询结果中的任意一个值即满足
SELECT name FROM students
WHERE score > ANY (
SELECT score FROM students WHERE age = 20
);
-- ALL: 必须大于子查询结果中的所有值才满足
SELECT name FROM students
WHERE score > ALL (
SELECT score FROM students WHERE age = 20
);
-- 等价转换:>ALL 等价于 >MAX,>ANY 等价于 >MIN
关联子查询 vs 非关联子查询
- 非关联子查询:子查询独立于外部查询,只执行一次。如:
WHERE score > (SELECT AVG(score) FROM students) - 关联子查询:子查询引用了外部查询的列,对外部每一行都会执行一次。如:
WHERE EXISTS (SELECT 1 FROM scores WHERE student_id = s.id) - 性能考虑:非关联子查询通常更快;关联子查询在大数据量时可能很慢,必要时用 JOIN 或 CTE 替代
实战任务
- 使用 EXISTS 查询有选修记录的学生
- 使用 >ALL 查询比所有一年级学生分数都高的学生
- 对比 EXISTS 和 IN 的查询结果和性能差异