1. 为什么需要阶段性总结SQL刷题经验
在力扣平台刷SQL题的过程中,我发现很多学习者(包括我自己)都容易陷入"刷了就忘"的困境。特别是当题目数量积累到50题左右时,各种查询模式、函数用法和优化技巧开始在大脑中打架。这时候做个阶段性总结,比盲目追求刷题数量重要得多。
我选择以50题为一个总结节点,主要基于三个考虑:
- 50题足够覆盖SQL的绝大多数核心语法(JOIN、子查询、窗口函数等)
- 这个题量已经能形成一定的解题模式识别能力
- 再往上刷如果不及时总结,边际效益会明显递减
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 高频SQL题型分类与解题套路
2.1 基础查询与过滤
这部分看似简单,但实际包含了SQL最核心的思维模式。典型题目包括:
- 简单SELECT查询(力扣175题:组合两个表)
- WHERE条件过滤(力扣182题:查找重复的电子邮箱)
- NULL值处理(力扣584题:寻找用户推荐人)
关键技巧:
sql复制-- NULL值处理的正确方式
SELECT name FROM customer WHERE referee_id != 2 OR referee_id IS NULL;
-- 注意不能直接用=或!=比较NULL
2.2 表连接与联合查询
JOIN操作是SQL的核心难点之一,常见题型:
- 内连接(力扣181题:超过经理收入的员工)
- 左/右外连接(力扣183题:从不订购的客户)
- 自连接(力扣197题:上升的温度)
提示:自连接处理时间序列问题时,DATE_ADD/INTERVAL函数比直接比较日期更可靠
2.3 聚合与分组统计
这部分考察GROUP BY和聚合函数的灵活运用:
- 基础分组(力扣182题:查找重复的电子邮箱)
- HAVING过滤(力扣586题:订单最多的客户)
- 多字段分组(力扣512题:游戏玩法分析II)
常见坑点:
- SELECT中的非聚合字段必须出现在GROUP BY中
- WHERE和HAVING的执行顺序不同(先WHERE过滤再分组)
2.4 子查询与临时表
子查询是解决复杂问题的利器:
- 标量子查询(力扣197题:上升的温度)
- 派生表(力扣185题:部门工资前三高的员工)
- EXISTS/NOT EXISTS(力扣262题:行程和用户)
优化建议:
- 能用JOIN解决的问题尽量不用子查询
- 大数据量时考虑使用WITH创建CTE(公共表表达式)
3. 窗口函数:SQL中的超级武器
窗口函数是SQL进阶的必备技能,典型应用场景:
3.1 排名问题
sql复制-- 力扣185题:部门工资前三高的员工
SELECT
d.name AS Department,
e.name AS Employee,
e.salary AS Salary
FROM (
SELECT
*,
DENSE_RANK() OVER (PARTITION BY departmentId ORDER BY salary DESC) AS rnk
FROM Employee
) e
JOIN Department d ON e.departmentId = d.id
WHERE e.rnk <= 3;
3.2 移动平均/累计求和
sql复制-- 力扣1321题:餐馆营业额变化增长
SELECT
visited_on,
amount,
ROUND(amount/7, 2) AS average_amount
FROM (
SELECT
visited_on,
SUM(SUM(amount)) OVER (ORDER BY visited_on ROWS 6 PRECEDING) AS amount
FROM Customer
GROUP BY visited_on
) t
WHERE visited_on >= (SELECT MIN(visited_on) FROM Customer) + 6;
3.3 前后记录比较
sql复制-- 力扣197题:上升的温度(窗口函数解法)
SELECT id
FROM (
SELECT
id,
recordDate,
temperature,
LAG(temperature) OVER (ORDER BY recordDate) AS prev_temp,
LAG(recordDate) OVER (ORDER BY recordDate) AS prev_date
FROM Weather
) t
WHERE temperature > prev_temp
AND DATEDIFF(recordDate, prev_date) = 1;
4. 性能优化实战技巧
4.1 索引使用原则
- 为JOIN字段和WHERE条件字段建立索引
- 复合索引遵循最左前缀原则
- 避免在索引列上使用函数或计算
4.2 执行计划解读
使用EXPLAIN分析查询:
sql复制EXPLAIN
SELECT e.name FROM Employee e
WHERE e.salary > (SELECT AVG(salary) FROM Employee);
关键指标:
- type列:最好到range级别,避免ALL(全表扫描)
- Extra列:注意是否出现"Using filesort"或"Using temporary"
4.3 常见优化模式
- 用JOIN代替IN子查询
- 限制返回字段而非使用SELECT *
- 大数据量表分页时使用游标而非OFFSET
- 定期分析表(ANALYZE TABLE)更新统计信息
5. 错题本:那些年踩过的坑
5.1 NULL值处理陷阱
sql复制-- 错误示例(不会返回referee_id为NULL的记录)
SELECT name FROM customer WHERE referee_id != 2;
-- 正确写法
SELECT name FROM customer WHERE referee_id != 2 OR referee_id IS NULL;
5.2 时间比较的时区问题
sql复制-- 可能因时区导致意外结果
SELECT * FROM orders WHERE order_date > '2023-01-01';
-- 更安全的写法
SELECT * FROM orders WHERE order_date > '2023-01-01 00:00:00';
5.3 GROUP BY的字段选择
sql复制-- 错误示例(name不在GROUP BY中)
SELECT department, name, AVG(salary)
FROM employees
GROUP BY department;
-- 正确写法
SELECT department, GROUP_CONCAT(name), AVG(salary)
FROM employees
GROUP BY department;
6. 刷题方法论与学习资源
6.1 高效刷题三步法
- 第一遍:独立解题(至少思考15分钟)
- 第二遍:学习最优解(比较执行计划)
- 第三遍:同类题目专项训练
6.2 推荐学习路径
- 基础语法:力扣简单题50道
- 中级技能:力扣中等题30道(重点JOIN和子查询)
- 高级进阶:力扣困难题20道(窗口函数和性能优化)
6.3 实用工具推荐
- SQLFiddle:在线SQL测试平台
- db-fiddle.com:支持多种数据库版本
- MySQL执行计划可视化工具(如Workbench)
在实际刷题过程中,我发现建立自己的"解题模式库"特别重要。比如遇到"求第N高"类问题,立即想到DENSE_RANK();遇到"连续日期"问题,考虑自连接或窗口函数。这种模式识别能力,才是刷题真正的价值所在。
