☰
SQL窗口函数与复杂查询实战:力扣高频50题精解
2026/10/29 9:05:55 网站建设 项目流程

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

实际工作中,连接性能优化是关键。我通常会:

  1. 优先使用INNER JOIN
  2. 为连接字段建立索引
  3. 控制连接表数量(超过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 索引策略

高频题目中常见的索引优化场景:

  1. 复合索引顺序:遵循最左前缀原则
  2. 覆盖索引:避免回表操作
  3. 函数索引:解决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' END

5.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. 学习路线建议

根据刷题经验,我建议的学习路径:

  1. 基础阶段(2周)

    • SELECT基础查询
    • WHERE条件过滤
    • 单表聚合函数
  2. 进阶阶段(3周)

    • 多表连接
    • 子查询
    • 基础窗口函数
  3. 精通阶段(4周)

    • 复杂窗口函数
    • 递归查询
    • 查询优化

每周保持15-20题的练习量,重点不是刷题数量,而是每道题至少掌握2-3种解法。我个人的错题本方法很有效:对每个错误记录场景还原、错误原因和正确解法。

7. 面试实战技巧

技术面试中SQL考察的典型模式:

  1. 现场编写:45分钟内完成3-5题
  2. 方案设计:设计数据库结构解决业务问题
  3. 性能优化:分析并改进现有SQL

应对策略:

  • 先明确需求再动手
  • 边写边解释思路
  • 主动讨论边界情况

例如被问到"查询每个部门薪资最高的员工"时,可以:

  1. 提出使用窗口函数的方案
  2. 对比GROUP BY方案的区别
  3. 讨论并列第一时的处理方式

8. 工具与资源推荐

高效刷题的工具链:

  1. 本地环境

    • MySQL 8.0(支持完整窗口函数)
    • DBeaver(多功能数据库客户端)
    • SQLite(轻量级练习)
  2. 学习资源

    • 《SQL进阶教程》
    • LeetCode SQL题解区
    • 数据库官方文档
  3. 调试技巧

    • 使用CTE分步调试复杂查询
    • 利用VALUES快速构建测试数据
    • 可视化执行计划工具

在最近的招聘季,我帮助团队优化SQL笔试题目时,特别增加了对窗口函数和执行计划的考察比重,这能更好区分候选人的真实水平。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询