子查询入门,从零理解 Subquery
前面我们已经掌握了各种 JOIN。从本篇开始,我们学习 SQL 中另一项核心能力------子查询(Subquery)。
很多 LeetCode 中等题,都会用到子查询。
一、什么是子查询?
子查询:
一个 SQL 查询嵌套在另一个 SQL 查询里面。
例如:
SELECT *
FROM Employee
WHERE salary >
(
SELECT AVG(salary)
FROM Employee
);
里面:
SELECT AVG(salary)
FROM Employee
就是子查询。
外层 SQL 使用子查询的结果继续筛选。
二、执行顺序
数据库首先执行:
SELECT AVG(salary)
FROM Employee;
假设结果:
6500
那么整个 SQL 相当于:
SELECT *
FROM Employee
WHERE salary > 6500;
所以:
子查询通常先执行,再把结果交给外层查询。
三、返回一个值(标量子查询)
最常见的子查询。
例如:
查询工资最高的人:
SELECT *
FROM Employee
WHERE salary=
(
SELECT MAX(salary)
FROM Employee
);
里面:
MAX(salary)
只返回一个值。
因此:
可以直接比较。
四、返回一列
例如:
SELECT *
FROM Orders
WHERE customerId IN
(
SELECT id
FROM Customers
WHERE country='China'
);
子查询:
返回:
1
5
8
10
外层:
使用:
IN
判断。
五、返回一张表
子查询也可以作为临时表。
例如:
SELECT *
FROM
(
SELECT
departmentId,
AVG(salary) avg_salary
FROM Employee
GROUP BY departmentId
) t;
这里:
子查询返回:
一张新的结果表。
外层:
把它当普通表继续查询。
六、子查询出现的位置
WHERE
最常见。
WHERE salary>
(
SELECT AVG(salary)
FROM Employee
)
FROM
作为临时表。
FROM
(
...
) t
必须起别名。
SELECT
也可以。
例如:
SELECT
name,
(
SELECT COUNT(*)
FROM Orders o
WHERE o.customerId=c.id
) AS order_cnt
FROM Customers c;
不过这种写法效率通常不高。
七、LeetCode 高频题
① 高于平均工资
SELECT *
FROM Employee
WHERE salary >
(
SELECT AVG(salary)
FROM Employee
);
② 最高工资
SELECT *
FROM Employee
WHERE salary=
(
SELECT MAX(salary)
FROM Employee
);
③ 某些用户的订单
WHERE customerId IN
(
SELECT ...
)
八、子查询与 JOIN 如何选择?
很多题:
JOIN 和子查询都能完成。
例如:
查询部门平均工资。
可以:
先 GROUP BY。
也可以:
子查询。
原则:
-
逻辑简单,子查询更容易理解。
-
多表关联频繁,JOIN 更直观。
-
实际工作中,两者通常可以互相转换。
九、常见错误
错误一
子查询返回多行,却使用:
=
例如:
WHERE id=
(
SELECT id
FROM ...
)
如果返回多个 id,就会报错。
应该使用:
IN
错误二
FROM 子查询忘记别名。
错误:
FROM
(
SELECT ...
)
正确:
FROM
(
SELECT ...
) t
错误三
认为子查询一定慢。
现代数据库优化器会对很多子查询进行优化。
真正决定性能的是:
-
索引
-
数据量
-
执行计划
而不是是否使用子查询。
十、本章总结
今天我们认识了 SQL 中的子查询:
-
标量子查询(返回一个值)
-
列子查询(返回一列)
-
表子查询(返回一张临时表)
理解子查询之后,下一篇我们将学习 LeetCode 高频考点------EXISTS 与 NOT EXISTS,它们是判断数据是否存在的高效工具,也是面试中的经典知识点。