1. 项目概述
"力扣高频 SQL 50 题阶段总结(五)"是面向数据库开发者和数据分析师的实战性技术总结系列。这个系列聚焦LeetCode平台上最具代表性的50道SQL题目,通过分类解析和实战演练帮助读者系统掌握SQL核心技能。作为第五篇阶段性总结,本文将深入剖析窗口函数、复杂连接查询等进阶SQL技术点。
对于正在准备技术面试或希望提升数据库操作能力的开发者而言,这类题目总结具有极高的参考价值。LeetCode作为知名的编程练习平台,其SQL题库覆盖了从基础到高级的各类场景,而高频50题更是浓缩了实际工作中最常见的查询需求和技术难点。
2. 核心题目类型解析
2.1 窗口函数应用
窗口函数是SQL进阶必须掌握的利器,在处理排名、累计和移动平均等场景时尤为高效。典型题目包括:
- 计算部门薪资排名(RANK/DENSE_RANK)
- 求累计销售额(SUM OVER)
- 计算移动平均(ROWS BETWEEN)
以经典的"部门工资前三高的员工"为例,解决方案通常结合DENSE_RANK和PARTITION BY:
SELECT Department, Employee, Salary FROM ( SELECT d.name AS Department, e.name AS Employee, e.salary AS Salary, DENSE_RANK() OVER (PARTITION BY d.id ORDER BY e.salary DESC) AS rnk FROM Employee e JOIN Department d ON e.departmentId = d.id ) ranked WHERE rnk <= 3注意:窗口函数执行顺序在WHERE之后,因此需要先构建子查询再过滤排名结果。
2.2 复杂连接查询
多表连接是SQL题目的另一大核心考点,常见模式包括:
- 自连接处理层级关系
- 左连接保留主表记录
- 全外连接合并结果集
"查找连续出现至少三次的数字"这类题目就需要巧妙的表自连接:
SELECT DISTINCT l1.Num AS ConsecutiveNums FROM Logs l1 JOIN Logs l2 ON l1.Id = l2.Id - 1 JOIN Logs l3 ON l1.Id = l3.Id - 2 WHERE l1.Num = l2.Num AND l2.Num = l3.Num实际工作中,连接性能优化是关键。我通常会:
- 优先使用INNER JOIN
- 为连接字段建立索引
- 控制连接表数量(超过3表需考虑重构)
3. 高频题目精讲
3.1 第N高薪水问题
这类题目考察对LIMIT和OFFSET的灵活运用,标准解法:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGIN SET N = N - 1; RETURN ( SELECT DISTINCT salary FROM Employee ORDER BY salary DESC LIMIT 1 OFFSET N ); END但实际面试中,面试官更期待你能指出:
- 性能问题:大数据量时OFFSET效率低下
- 边界情况:N值超过记录数时的处理
- 替代方案:使用窗口函数可能更优
3.2 分数排名问题
考察对排名函数的深入理解,DENSE_RANK与RANK的区别至关重要:
SELECT score, DENSE_RANK() OVER (ORDER BY score DESC) AS 'rank' FROM Scores我曾在一个电商项目中,就因混淆两者导致促销活动排名出错。关键区别:
- RANK:并列会跳过后续名次(1,2,2,4)
- DENSE_RANK:并列不跳名次(1,2,2,3)
4. 实战优化技巧
4.1 执行计划分析
遇到性能问题时,EXPLAIN是首要工具。重点关注:
- 是否使用索引(type列)
- 扫描行数(rows列)
- 临时表使用(Extra列)
例如,对于慢查询:
EXPLAIN SELECT * FROM orders WHERE customer_id IN ( SELECT id FROM customers WHERE reg_date > '2023-01-01' )优化方案可能是改为JOIN:
EXPLAIN SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.reg_date > '2023-01-01'4.2 索引策略
高频题目中常见的索引优化场景:
- 复合索引顺序:遵循最左前缀原则
- 覆盖索引:避免回表操作
- 函数索引:解决WHERE条件中的函数计算
在"查找重复电子邮箱"题目中:
-- 低效写法 SELECT Email FROM Person GROUP BY Email HAVING COUNT(*) > 1 -- 优化方案 CREATE INDEX idx_email ON Person(Email);5. 常见问题与解决方案
5.1 NULL值处理陷阱
SQL中NULL的特殊性常导致意外结果,例如:
-- 错误:NULL比较 SELECT * FROM table WHERE column = NULL -- 正确写法 SELECT * FROM table WHERE column IS NULL在"交换工资"题目中,需要注意NULL安全的更新方式:
UPDATE salary SET sex = CASE WHEN sex = 'm' THEN 'f' ELSE 'm' END5.2 日期计算问题
日期函数存在数据库差异,MySQL和SQL Server处理方式不同:
-- MySQL 昨天 WHERE date = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) -- SQL Server WHERE date = DATEADD(day, -1, CAST(GETDATE() AS DATE))在"最近30天活跃用户"类题目中,必须考虑时区问题。
6. 学习路线建议
根据刷题经验,我建议的学习路径:
基础阶段(2周)
- SELECT基础查询
- WHERE条件过滤
- 单表聚合函数
进阶阶段(3周)
- 多表连接
- 子查询
- 基础窗口函数
精通阶段(4周)
- 复杂窗口函数
- 递归查询
- 查询优化
每周保持15-20题的练习量,重点不是刷题数量,而是每道题至少掌握2-3种解法。我个人的错题本方法很有效:对每个错误记录场景还原、错误原因和正确解法。
7. 面试实战技巧
技术面试中SQL考察的典型模式:
- 现场编写:45分钟内完成3-5题
- 方案设计:设计数据库结构解决业务问题
- 性能优化:分析并改进现有SQL
应对策略:
- 先明确需求再动手
- 边写边解释思路
- 主动讨论边界情况
例如被问到"查询每个部门薪资最高的员工"时,可以:
- 提出使用窗口函数的方案
- 对比GROUP BY方案的区别
- 讨论并列第一时的处理方式
8. 工具与资源推荐
高效刷题的工具链:
本地环境
- MySQL 8.0(支持完整窗口函数)
- DBeaver(多功能数据库客户端)
- SQLite(轻量级练习)
学习资源
- 《SQL进阶教程》
- LeetCode SQL题解区
- 数据库官方文档
调试技巧
- 使用CTE分步调试复杂查询
- 利用VALUES快速构建测试数据
- 可视化执行计划工具
在最近的招聘季,我帮助团队优化SQL笔试题目时,特别增加了对窗口函数和执行计划的考察比重,这能更好区分候选人的真实水平。