LeetCode SQL 从入门到精通(MySQL)06(上)

子查询入门,从零理解 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,它们是判断数据是否存在的高效工具,也是面试中的经典知识点。

相关推荐
敲上瘾15 分钟前
Redis持久化存储机制:从RDB到AOF再到混合持久化的配置与实践
linux·数据库·redis·缓存
circuitsosk2 小时前
NL2SQL在工业级场景下的精度优化:Schema Linking + 动态Few-shot实战
人工智能·python·sql·大模型·nl2sql
2401_894915534 小时前
GEO 优化源码全解析:从搜索引擎到 AI 引擎的底层改写逻辑
java·服务器·前端·数据库·人工智能·分布式·搜索引擎
正儿八经的少年8 小时前
布隆过滤器(解决redis缓存穿透步骤之一)
数据库·redis·缓存
xrandzj9 小时前
MySQL8.0 从零通关核心操作手册(Ubuntu实战版)
数据库·mysql
我不会插花弄玉9 小时前
4.数据类型【由浅入深-MySQL】
数据库·mysql
denggun123459 小时前
yield
前端·数据库·python
ltl9 小时前
SQLite Rollback Journal:写前拷贝与提交点
数据库
ltl10 小时前
TiFlash Learner:Raft 日志如何进列存
数据库
ltl10 小时前
BM25 与 Lucene Similarity:公式如何落到 postings
数据库