1. 这50题刷到第四阶段,题型开始出现明显分层
先交代下背景。这个阶段总结系列写到第四期,说明50道题已经推进到后半程了。和前三期比起来,最直观的感受是:题目开始从“这个函数你学过没有”转向“你知不知道该在什么时候用它”。到这一阶段,每道题涉及的考点可能不超过三个,但每个考点都要真正吃透才能顺下去,否则很容易出现一种情况——看题觉得眼熟,写出来跑不过,再看别人的解法觉得自己白刷了。
从题型分布上看,这一阶段的高频题有几个明显的集中点:排名与TopN问题、连续性问题、分组聚合后的过滤、日期区间的处理、以及各种“去重”的变体。这些知识点单拎出来都能写一篇长文,但在力扣的SQL题里,它们往往是组合出现的。比如一道题考的是“每个部门工资前三名”,实际拆开就是窗口函数加分组加排序三个考点叠在一起。
我刷到这里的一个体会是:前期的题偏重单点语法,比如JOIN怎么写、WHERE怎么过滤;到了后期,题目会更像一个小型业务需求,你需要自己判断先做什么后做什么,而不是照着题目里的提示机械翻译成SQL。这个转折点大概出现在第30题之后,越往后越明显。
另外值得注意的一点是,到了第四阶段,题目对执行效率的要求明显上升。有些写法在数据量小的时候看不出问题,但一旦表里数据量上到一定量级,慢查询、超时、内存溢出这些问题就全冒出来了。力扣的SQL题虽然不像真实业务那样有海量数据,但它会通过隐藏的边界用例来逼你去优化写法,这也是刷题的价值所在。
所以这一篇总结,我不会按题号顺序写流水账,而是把这一阶段最值得讲的知识点、踩过的坑、以及一道有代表性的题目完整复盘出来,给大家一个可以照着复盘的思路。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 窗口函数在这轮刷题里出现的频率极高
2.1 排名类问题:ROW_NUMBER、RANK、DENSE_RANK 的差异
排名类问题是SQL题里的常青树,这一阶段几乎每两三题就会遇到一次。三个排名函数的区别,我在这里再精确地说一遍,因为每轮刷题都会有人在这上面丢分。
ROW_NUMBER():给每一行一个唯一的序号,相同值的行顺序随机,但序号不重复。
RANK():相同值的行获得相同排名,但下一个排名会跳过。比如两个并列第一,下一个就是第三。
DENSE_RANK():相同值的行获得相同排名,下一个排名不跳过。两个并列第一,下一个还是第二。
看起来很简单,但实际做题的时候坑藏在细节里。比如“每个部门工资最高的员工”这类题,用ROW_NUMBER就够了,因为只需要取一条;但如果是“每个班级成绩排名前两名的学生,且成绩相同要并列”,那就必须用DENSE_RANK或者RANK,用ROW_NUMBER会把并列的人丢掉。
还有一个容易忽略的点:这三个函数默认的排序方向是ASC,但排名问题几乎都是取最大值或者最小值,所以ORDER BY后面一定要记得写DESC。这属于看题不仔细的低级错误,但我在实际刷题中真的见过很多次,也包括我自己早期写漏过。
2.2 累计求和与移动窗口:ROWS BETWEEN 的边界设定
这一阶段出现了好几道和“累计”相关的题。比如求每个月的累计销售额、每个用户的累计下单金额,这类题需要用SUM加OVER配合ROWS BETWEEN来限定窗口范围。
我最早刷这类题的时候,总觉得ROWS BETWEEN是个可有可无的修饰,直到遇到一道要求“统计截至当前日期前90天的累计值”的题,才发现不限定窗口边界,函数默认会把整个分区都算进去,结果完全不对。
ROWS BETWEEN 的常见写法有三种:
- ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:从分区第一行到当前行,这是最常见的累计写法
- ROWS BETWEEN N PRECEDING AND CURRENT ROW:从当前行往前N行到当前行,适合滑动窗口
- ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING:从当前行到分区最后一行,适合“未来累计”的场景
注意一点,如果不写ROWS BETWEEN,窗口函数默认的范围是“从分区第一行到当前行”,对于SUM来说效果等同于第一种写法,但对AVG、COUNT这些函数来说,默认行为和你想的可能不一样,尤其是涉及ORDER BY的时候。
