SQL面试中窗口函数的真正价值与高级用法
SQL窗口函数的核心价值在于表达分组排序范围内计算的意图,而非炫技。需理解partition、order、frame三个概念。性能上应先缩小数据范围再开窗。连续登录利用日期减排名构造分组键。LAG函数需注意日期连续性。
先说说后端面试里那些绕不开的SQL题。每组取TopN、连续登录、同比环比、累计求和,几乎是必考题。很多同学一看到这类需求,条件反射就是“上窗口函数”。但窗口函数不是用来炫技的,它的核心价值在于表达一种意图:在某个分组和排序范围内进行计算。

会用窗口函数,重点不是死记硬背 row_number() 的语法,而是真正理解 partition(分组)、order(排序) 和 frame(窗口框架) 各自在描述什么。
每组 TopN,窗口函数的经典开场
题目很典型:每个部门取工资最高的 3 个人。
SELECT *FROM ( SELECT employee_id, department_id, salary, ROW_NUMBER() OVER ( PARTITION BY department_id ORDER BY salary DESC ) AS rn FROM employee) tWHERE rn <= 3;
这个 PARTITION BY department_id 就是灵魂——它告诉数据库,每个部门单独开一个排名场。而 ORDER BY salary DESC 决定了排名依据。这比写子查询或者自连接清爽太多了。
窗口函数的执行逻辑,一张图说明白
flowchart TD A[原始数据] --> B[按 partition 分组] B --> C[组内排序] C --> D[计算窗口函数] D --> E[外层过滤]
窗口函数跟 group by 最大的区别是什么?前者是在结果行上“附加”一个计算值,不会把多行数据压成一行。这是很多新手容易混淆的地方——以为窗口函数会改变行数,其实它不会。
row_number、rank、dense_rank:并列怎么处理?
假设工资是 [100, 100, 90]:
row_number: 1, 2, 3rank: 1, 1, 3dense_rank: 1, 1, 2
面试时别想当然地直接用 row_number。题目说“取前三名”,那并列的两个人算不算都要保留?一定要先问清楚业务意图。这个细节比你会写哪种函数重要得多。
性能这块,大多数人容易忽略
窗口函数本质上需要排序。大表上跑窗口函数,笔者的建议是:先考虑分区字段、排序字段和过滤条件。能先缩小数据范围,就别全表开窗。
WHERE dt = '2026-07-03'
就是这么一句简单的分区过滤,往往比你花里胡哨地换十种窗口写法都管用。
连续登录也是高频题。思路核心是:用日期减去排名,构造出一个分组键。同一段连续日期内,这个差值是一样的。
SELECT user_id, MIN(login_date), MAX(login_date), COUNT(*)FROM ( SELECT user_id, login_date, DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY) AS grp FROM user_login) tGROUP BY user_id, grp;
这道题的关键是:把“连续”这个抽象概念,转成具体的“同组”标识。窗口函数只是帮你实现这个转化的工具,核心洞察才是真正的答案。
还有一个经常被忽略的细节:同一天登录多次,算一次还是多次?题目没说,得先弄清楚去重规则。
同比环比场景下,LAG 函数很常用。它能拿到上一行的数据,但上一行是不是昨天、上周或者上月,取决于排序和数据是否完整。如果日期本身不连续,直接用 LAG 可能拿到一个完全错误的基准。
SELECT dt, gmv, LAG(gmv, 1) OVER (ORDER BY dt) AS prev_gmvFROM ads_daily_gmv;
这段代码只适合日期连续的场景。如果日期有空缺,需要先补一张日历表。面试时能指出这个边界条件,会让面试官觉得你考虑得很周全。
总结
SQL 窗口函数的真正价值,在于能够清晰地表达“在分组和排序范围内进行计算”的意图,无论是排名、累计、还是偏移量。重点是把 partition、order、frame 这三个概念理解透,而不是机械地背几个函数名。
窗口函数不是为了写得高级,而是为了把“组内计算”这件事说清楚、写简洁。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
SQL Server多用户并发INSERT幻读解决方案
SQLServer中幻读源于“先查后插”业务的间隙漏洞,SERIALIZABLE隔离级别不能覆盖多语句操作且依赖索引。真正解决需将“读-判-写”绑定为原子动作,如使用MERGE语句、唯一索引加错误捕获或UPDLOCK加HOLDLOCK手动锁范围,并确保查询走索引及显式开启事务。
Django项目利用安全库规避SQL注入的方法
DjangoORM仅对值参数化,字段名等结构参数需白名单校验。filter()动态字段名、raw()和extra()参数化、RawSQL中LIKE手动转义及ORDERBY等结构字段均为注入风险点,需严格规避用户直接控制。
SQL分组统计状态变更次数的方法
通过LAG()窗口函数对比相邻行状态变化并计数,是统计分组内状态改变次数的核心方法。需严格按业务逻辑排序、正确分区,并处理NULL边界。旧版MySQL可考虑导出数据用脚本处理。性能优化需建立复合索引,避免函数影响。状态定义需明确连续相同值过滤等陷阱。
MySQL数据排序的原理与实现步骤
MySQL排序采用文件排序或索引排序,数据量大时使用合并排序。内存排序由sort_buffer_size控制,超限则转磁盘临时表。索引排序效率高,覆盖索引可避免回表。通过EXPLAIN可分析是否使用索引、临时表或文件排序,据此优化性能。
如何定位MySQL撤销日志页锁定导致的检查点延迟
UndoLog页被锁定本身不直接导致CheckPoint延迟,根因是长事务阻塞purge线程导致undo记录无法清理。通过Historylistlength超万且增长、PURGEPROCESSED停滞、事务ID与清理ID差距扩大可判断。定位需查最老活跃事务及其undo段与purge线程状态。
- 热门数据榜
相关攻略
2026-07-12 07:09
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
2026-07-12 07:08
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

