面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了

上个月面一家大厂,技术面第二轮,面试官出了一个SQL题:"查每个部门工资最高的员工。" 我脑子里闪过一堆解法:子查询、自连接、group by......但都太绕,而且还容易漏掉并列第一。我打开Cursor,输入:"用窗口函数写一个SQL,查出每个部门工资最高的员工,如果最高工资并列全部返回。" 三秒后SQL生成。面试官看了一眼,说:"你是我见过第一个用窗口函数还讲得清原理的候选人。" 后来我拿到了offer。

前言

SQL面试题里,"分组取Top N"是经典中的经典。尤其是"每个部门工资最高的员工",考频率仅次于两数之和。很多人能写出来,但写出来的往往是子查询嵌套自连接,性能差、代码丑、还容易漏掉并列的情况。

而窗口函数(ROW_NUMBER / RANK / DENSE_RANK)才是这道题的标准答案,但很多人一紧张就忘了语法:OVER里面怎么写?PARTITION BY和ORDER BY怎么配?RANK和ROW_NUMBER有什么区别?

其实不用背,AI一秒就给你写出来。但关键是:你要能讲清楚为什么选这个函数,以及窗口函数的执行顺序。今天我就用这个真实面试题,教你用AI秒解SQL难题,顺便讲透窗口函数。

金句:面试官考的不是你背不背得出语法,而是你懂不懂"为什么"和"选哪个"。

一、先看面试题原貌

表结构

sql 复制代码
CREATE TABLE employee (
    id INT,
    name VARCHAR(50),
    department VARCHAR(50),
    salary INT
);

需求:查询每个部门工资最高的员工。如果最高工资有并列(比如两人都是10000),都要返回。

示例数据

id name department salary
1 张三 技术部 12000
2 李四 技术部 10000
3 王五 技术部 12000
4 赵六 销售部 9000

期望输出:技术部返回张三和王五(并列12000),销售部返回赵六。

二、AI生成的标准答案

我在Cursor里输入:

用MySQL语法,写一个SQL查询:每个部门工资最高的员工。如果最高工资有多人,全部返回。要求使用窗口函数,并解释执行顺序。

AI输出:

sql 复制代码
WITH ranked AS (
    SELECT 
        *,
        RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk
    FROM employee
)
SELECT id, name, department, salary
FROM ranked
WHERE rnk = 1;

为什么用 RANK 而不是 ROW_NUMBER?

  • ROW_NUMBER 会给每人一个唯一序号,并列的也会强行分出先后,导致只能返回一人。
  • RANK 会为相同工资分配相同排名,并列第一就都返回。

面试官紧接着追问:那 DENSE_RANK 呢?答:DENSE_RANK 排名连续,但本题只需要最高工资,效果与 RANK 一样(因为只取 rnk=1)。但如果有第二高需求,DENSE_RANKRANK 区别就大了。

三、窗口函数的执行顺序(讲清楚才能加分)

面试官接着问:"窗口函数是在SQL哪个阶段执行的?"

我回答:在WHERE、GROUP BY之后,在ORDER BY之前。具体顺序:

  1. FROM → JOIN
  2. WHERE → 过滤行
  3. GROUP BY → 分组
  4. 聚合函数计算
  5. HAVING → 过滤分组
  6. 窗口函数 → 在这里计算排名
  7. ORDER BY
  8. LIMIT

所以,窗口函数的结果可以在WHERE里用吗?不能,因为WHERE在窗口函数之前执行。所以必须用CTE或子查询先计算排名,再在外部WHERE筛选。

AI生成的代码正是这样做的:WITH ranked AS ( ... ) 先算排名,再 WHERE rnk = 1。面试官听到这里,点了头。

四、如果不用窗口函数,你能写出更优的解法吗?

可以用子查询+关联,但性能差且代码臃肿:

sql 复制代码
SELECT e1.*
FROM employee e1
LEFT JOIN employee e2 
    ON e1.department = e2.department 
    AND e1.salary < e2.salary
WHERE e2.id IS NULL;

这个解法的逻辑是:找出不存在同部门更高工资的人。优点是跨数据库通用,缺点是不好理解,而且对于大表性能差(因为自连接扫描两次)。

用窗口函数,不仅快(一次扫描),而且清晰易维护。所以现代SQL强烈推荐。

金句:不用窗口函数的SQL优化,就像不用箭头函数的JS------能跑,但不优雅。

五、面试官为什么认可我用AI?

同样的逻辑:AI帮我生成语法,我负责解释原理。他知道我背不出完整的RANK语法(正常人谁背?),但我知道什么时候用RANK、窗口函数执行顺序、如何改造成其他需求。这就够了。

六、拓展:分组取第二名怎么改?

面试官可能接着问:"如果我要每个部门第二高工资呢?"

很简单,把 WHERE rnk = 1 改成 WHERE rnk = 2 就行。但注意:如果第二名是并列(比如两人都是9000),RANK会跳过第三名的序号(比如排名:1,2,2,4),DENSE_RANK 则连续(1,2,2,3)。你需要问清楚需求。

七、完整代码和测试数据

你可以用这个数据自测:

sql 复制代码
CREATE TABLE employee (
    id INT PRIMARY KEY,
    name VARCHAR(20),
    department VARCHAR(20),
    salary INT
);
INSERT INTO employee VALUES
(1,'张三','技术部',12000),
(2,'李四','技术部',10000),
(3,'王五','技术部',12000),
(4,'赵六','销售部',9000);

然后运行上面的窗口函数SQL,输出应该是:张三、王五、赵六。

八、写在最后

面试题在变,但考察的核心没变:理解原理 > 背诵语法。AI能帮你写出任何代码,但能讲清楚为什么、怎么改、有什么坑,才是你的真本事。

你面试遇到过哪些"想不起来语法"的瞬间?后来怎么过的?

相关推荐
文心快码BaiduComate1 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员
光辉GuangHui1 小时前
Agent Skill 也需要测试:如何搭建 Skill 评估框架
前端·后端·llm
小码工作室1 小时前
使用 HAVING 进行 MySQL 集合筛选
mysql
我是谁的程序员1 小时前
Mac 上生成 AppStoreInfo.plist 文件,App Store 上架
后端·ios
irving同学462381 小时前
Node 后端实战:JWT 认证与生产级错误处理
前端·后端
Master_Azur1 小时前
单元测试——Junit单元测试框架
后端
用户8356290780512 小时前
使用 Python 进行 Word 邮件合并
后端
罗超驿2 小时前
18.事务的隔离性和隔离级别:MySQL面试高频考点全解析
数据库·mysql·面试
用户8356290780512 小时前
Python 操作 PowerPoint OLE 对象
后端·python