SQL 面试题:窗口函数不是为了显得高级

📅 2026/7/3 15:39:08
SQL 面试题:窗口函数不是为了显得高级
SQL 面试题窗口函数不是为了显得高级后端面试里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 ) t WHERE 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 区别salary: 100, 100, 90 row_number: 1, 2, 3 rank: 1, 1, 3 dense_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 ) t GROUP BY user_id, grp;这类题最重要的是把“连续”转成“同组”。窗口函数只是工具核心观察才是答案。写 SQL 时也要问清去重规则。同一天登录多次是算一次还是多次题目没说就要先处理。窗口函数还常用于同比环比。LAG能拿到上一行但上一行是否就是昨天、上周、上月要看排序和数据完整性。日期缺失时直接 lag 可能拿错基准。SELECT dt, gmv, LAG(gmv, 1) OVER (ORDER BY dt) AS prev_gmv FROM ads_daily_gmv;这段只适合日期连续的情况。如果日期不连续要先补日历表。面试里能指出这个边界会显得很清醒。五、总结SQL 窗口函数用于在分组和排序范围内计算排名、累计、偏移等结果。关键是理解 partition、order、frame而不是背高级语法。窗口函数不是为了显得高级是为了把“组内计算”说清楚。