跳到正文
ChatRound
  1. ChatRound
  2. 示例
  3. 代码

每个部门工资前三档的人:AI 写的 SQL,核对了一遍

Gemini 2.5 Flash-Lite 的查询本身没错,但解释里举的例子把 RANK() 跳过哪一名说错了。

示例下面的回答是我们为这个页面让 Gemini 2.5 Flash-Lite 写的,通过 Google 的 API 调用,没开联网搜索,不是任何人的真实对话。ChatRound 在 2026年10月27日 核对了它。核对用的是 ChatRound 对这家公司的回答默认挑选的两个模型。

Gemini 2.5 Flash-Lite 的回答 写一条 SQL:从 employees(id, name, department_id, salary) 表里,查出每个部门工资排前三档的所有人。工资一样的要一起列出来。
WITH RankedEmployees AS (
    SELECT
        id,
        name,
        department_id,
        salary,
        DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) as salary_rank
    FROM
        employees
)
SELECT
    id,
    name,
    department_id,
    salary
FROM
    RankedEmployees
WHERE
    salary_rank <= 3
ORDER BY
    department_id, salary DESC;

解释:

  1. WITH RankedEmployees AS (...): 这是一个公共表表达式 (CTE),它创建了一个名为 RankedEmployees 的临时结果集。CTE 可以让 SQL 查询更具可读性和组织性。

  2. SELECT id, name, department_id, salary, DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) as salary_rank FROM employees:

    • 我们从 employees 表中选择 id, name, department_id, 和 salary 列。
    • DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC): 这是关键部分,使用了窗口函数 DENSE_RANK()。
      • PARTITION BY department_id: 这会将数据按照 department_id 分组。DENSE_RANK() 会为每个部门独立计算排名。
      • ORDER BY salary DESC: 在每个部门内部,我们按照 salary 从高到低进行排序。
      • DENSE_RANK(): 这个函数会给每个工资等级分配一个排名。如果工资相同,它们会获得相同的排名,并且不会跳过下一个排名。例如,如果工资最高的是 10000,第二高的是 9000,但有两个人的工资都是 9000,那么这两个人都会被认为是排名第 2,下一个排名将是第 3(而不是跳过第 2,直接到第 3)。这正是我们想要的“工资一样的要一起列出来”的要求。
    • as salary_rank: 我们将计算出的排名命名为 salary_rank。
  3. SELECT id, name, department_id, salary FROM RankedEmployees WHERE salary_rank <= 3:

    • 我们从刚刚创建的 RankedEmployees CTE 中选择所有需要的列。
    • WHERE salary_rank <= 3: 这里我们过滤出 salary_rank 小于或等于 3 的所有行。这意味着我们选择了每个部门中工资排名前三档的所有员工。
  4. ORDER BY department_id, salary DESC:

    • 最后,我们按照 department_id 和 salary (降序) 对最终结果进行排序,以便清晰地查看每个部门的排名情况。

为什么使用 DENSE_RANK() 而不是 RANK() 或 ROW_NUMBER()?

  • ROW_NUMBER(): 会为每一行分配一个唯一的序列号。如果工资相同,它们会获得不同的排名,不符合要求。
  • RANK(): 如果工资相同,它们会获得相同的排名,但会跳过下一个排名。例如,如果有两个人并列第一,那么下一个排名是第三。
  • DENSE_RANK(): 如果工资相同,它们会获得相同的排名,并且不会跳过下一个排名。这是最符合“工资一样的要一起列出来”的要求的。

核心 SQL 可以信,但排名示例把 RANK() 的跳号说错;还应补充 NULL 和数据库版本注意事项。

  • 1 有错
  • 0 有争议
  • 5 没问题
  • 2 有遗漏

由 DeepSeek V4.1 Flash和Claude Haiku 4.5 核对 · 报告由 GPT-5.6 Luna 撰写

有错的地方

有错

这句话最后的对比说错了:以 10000、9000、9000、8000 为例,DENSE_RANK() 的结果是 1、2、2、3;RANK() 的结果是 1、2、2、4,即跳过第 3 名,而不是跳过第 2 名。

Gemini 2.5 Flash-Lite
例如,如果工资最高的是 10000,第二高的是 9000,但有两个人的工资都是 9000,那么这两个人都会被认为是排名第 2,下一个排名将是第 3(而不是跳过第 2,直接到第 3)。
DeepSeek V4.1 Flash
“以 10000、9000、9000、8000 为例,DENSE_RANK() 给出 1、2、2、3;而 RANK() 给出 1、2、2、4(跳的是第 3 档,不是"跳过第 2")。”

其余部分

没问题的地方5 条 ▾
  • 使用 DENSE_RANK() 按 department_id 分区、按 salary 降序排名,符合“前三档工资”的通常含义。
  • 相同工资的员工会获得相同排名,因此会被一起返回。
  • 使用 CTE 后在外层通过 salary_rank <= 3 过滤,写法和 SQL 执行逻辑正确。
  • ROW_NUMBER() 会拆散并列工资,RANK() 会因并列产生跳号;在“前三个不同工资档位”的语义下,DENSE_RANK() 更合适。
  • 按 department_id、salary DESC 排序可以让结果按部门和工资高低展示。
漏掉的要点2 条 ▾
  • 未说明 salary 为 NULL 时的处理;NULL 的默认排序位置具有数据库方言差异,可能被纳入排名或排在末尾,必要时应显式过滤或指定 NULLS LAST。
  • 未说明窗口函数的数据库兼容性,也未明确“前三档”是三个不同工资档位;若业务实际要求的是“最高的三个人(并列一起返回)”,排名函数和语义需要另行确认。
只有 1 个模型提到3 条 ▾
  • DeepSeek V4.1 Flash: department_id 为 NULL 的员工会被视为同一个独立分区,可能被当作一个“部门”返回。 值得核实
  • DeepSeek V4.1 Flash: 同一部门同一工资的员工之间没有稳定的输出顺序,如需可复现结果可增加 id 排序。 有用的角度
  • Claude Haiku 4.5: 可以通过具体示例数据和输出结果进一步说明并列第三档会全部返回,但这不是 SQL 正确性的必要条件。 有用的角度

改好的回答

WITH RankedEmployees AS (
    SELECT
        id,
        name,
        department_id,
        salary,
        DENSE_RANK() OVER (
            PARTITION BY department_id
            ORDER BY salary DESC
        ) AS salary_rank
    FROM employees
)
SELECT
    id,
    name,
    department_id,
    salary
FROM RankedEmployees
WHERE salary_rank <= 3
ORDER BY department_id, salary DESC, id;

DENSE_RANK() 会在每个部门内按不同工资档位排名:相同工资获得相同排名,且排名不会跳号,因此前三档工资的所有员工都会被返回。

例如工资为 10000、9000、9000、8000 时:

  • DENSE_RANK() 的排名是 1、2、2、3;
  • RANK() 的排名是 1、2、2、4;
  • ROW_NUMBER() 的排名是 1、2、3、4。

因此,若“前三档”指前三个不同的工资水平,应使用 DENSE_RANK()。如果业务要求的是“最高的三个人,并列者一起返回”,则应进一步确认是否使用 RANK() 以及并列跳号是否符合业务定义。

注意事项:

  • 如果 salary 允许为 NULL,应明确是否排除它们。若不参与榜单,可在 CTE 中加入 WHERE salary IS NOT NULL;也可以根据数据库方言显式指定 NULL 的排序位置,例如 PostgreSQL/Oracle 使用 NULLS LAST,MySQL 可使用 ORDER BY (salary IS NULL), salary DESC。
  • 如果 department_id 为 NULL,这些记录会共同形成一个 NULL 分区;若不应返回,应加入 WHERE department_id IS NOT NULL。
  • 窗口函数需要数据库版本支持,例如 MySQL 8.0+;MySQL 5.7 等旧版本需要改写为相关子查询或自连接。
  • 若需保证同部门同工资员工的输出顺序稳定,可在最终排序中增加 id。

我们的核对

这份报告发布前,我们读过一遍

我们在 SQLite 上用 10000、9000、9000、8000 跑过:DENSE_RANK() 是 1、2、2、3,RANK() 是 1、2、2、4,和报告说的一样。这条查询要用支持窗口函数的数据库,比如 MySQL 8.0 以上、SQLite 3.25 以上。

2026年10月28日 对照下面的资料核对。

资料来源:

每个核对模型的完整意见

DeepSeek V4.1 Flash▾

1. 我的答案

这个 SQL 的核心思路是对的:题目里"前三档"对应的是不同工资档位,而不是前三个人,所以用 DENSE_RANK() ... PARTITION BY department_id ORDER BY salary DESC 再筛 <= 3,是标准解法,并列工资会自动一起带出。它需要补的是边界条件:salary 或 department_id 为 NULL 时的行为(在 PostgreSQL / Oracle 里 ORDER BY salary DESC 默认把 NULL 排在最前,NULL 会被当成"最高档"),以及窗口函数对数据库版本的要求。说明文字里那段排名示例写错了。

2. 逐条核对

  • 用 DENSE_RANK() 而不是 RANK() / ROW_NUMBER() — holds。"前三档"(tier/档)在中文语境下指工资的不同档位,"工资一样的要一起列出来"进一步排除了 ROW_NUMBER();RANK() 虽然并列也一起出,但会跳号,会把"第 4 档"漏掉或错当成第 4 名。答案的选择和理由都对。
  • CTE + PARTITION BY department_id ORDER BY salary DESC 的结构 — holds。语法正确,分区内降序排名,筛选 salary_rank <= 3,语义与需求一致。
  • WHERE salary_rank <= 3 的作用 — holds。CTE 里别名可用、外层引用正确,没有在同一个 SELECT 的 WHERE 里引用窗口别名的常见错误。
  • ORDER BY department_id, salary DESC — holds(只是同一部门同一工资内部顺序不确定,见第 3 节)。
  • 示例里的排名解释 — wrong。原文:"如果工资最高的是 10000,第二高的是 9000,但有两个人的工资都是 9000,那么这两个人都会被认为是排名第 2,下一个排名将是第 3(而不是跳过第 2,直接到第 3)。"括号里那句是错的/不通的:以 10000、9000、9000、8000 为例,DENSE_RANK() 给出 1、2、2、3;而 RANK() 给出 1、2、2、4(跳的是第 3 档,不是"跳过第 2")。前面"下一个排名将是第 3"本身没错,错的是把它对比成了"跳过第 2"。

3. 漏掉的内容

  • NULL 工资的坑(最容易出错的一点):ORDER BY salary DESC 的 NULL 位置是方言相关的——PostgreSQL 和 Oracle 默认 NULLS FIRST(DESC 时 NULL 排最前),NULL 会被当成第 1 档直接入选;MySQL、SQL Server 默认把 NULL 排在最后,通常不会入选。如果 salary 可为空且不希望 NULL 参与,需要显式处理:PostgreSQL / Oracle 用 ORDER BY salary DESC NULLS LAST,MySQL 没有 NULLS LAST 语法,可用 ORDER BY (salary IS NULL), salary DESC。
  • department_id 为 NULL:会自成一个分区,单独输出一组"部门"记录。如果有这种脏数据,通常要加 WHERE department_id IS NOT NULL。
  • 方言与版本限制没有提:窗口函数需要 MySQL 8.0+ / MariaDB 10.2+ / SQLite 3.25+ / PostgreSQL / Oracle / SQL Server。老版本 MySQL 5.7 只能改用相关子查询或自连接,例如 SELECT * FROM employees e WHERE (SELECT COUNT(DISTINCT salary) FROM employees x WHERE x.department_id <=> e.department_id AND x.salary > e.salary) < 3(注意 <=> 处理 NULL,且需显式排除 NULL 工资)。
  • 结果顺序不确定:同部门同工资的人之间没有稳定的排序键,若要求可复现,加 , id。
  • 语义歧义未声明:如果业务真实口径是"每部门工资最高的 3 个人(含并列)",那应该用 RANK() <= 3。答案默认了"三档"= 三个不同工资档位,这个假设合理,但值得说明一句。
  • (可选)性能:(department_id, salary) 上的索引对 PARTITION BY department_id ORDER BY salary DESC 有帮助。

4. 修正后的答案

SQL 主体保持不变,只补 NULL 与方言处理:

WITH RankedEmployees AS (
    SELECT
        id,
        name,
        department_id,
        salary,
        DENSE_RANK() OVER (
            PARTITION BY department_id
            ORDER BY salary DESC
        ) AS salary_rank
    FROM employees
    WHERE salary IS NOT NULL          -- 若业务上允许 NULL 工资,删掉这行并改用下面的 NULLS 处理
      AND department_id IS NOT NULL
)
SELECT id, name, department_id, salary
FROM RankedEmployees
WHERE salary_rank <= 3
ORDER BY department_id, salary DESC, id;

如果必须保留 NULL 工资但又不想让它们占据榜单:

  • PostgreSQL / Oracle:ORDER BY salary DESC NULLS LAST
  • MySQL:ORDER BY (salary IS NULL), salary DESC

解释部分只改那一句示例:工资 10000、9000、9000、8000 时,DENSE_RANK() 得到 1、2、2、3(不跳号,所以 8000 是第 3 档);RANK() 得到 1、2、2、4(跳过第 3 档);ROW_NUMBER() 得到 1、2、3、4(并列被打散)。其余关于 CTE、PARTITION BY、以及为什么不用 RANK() / ROW_NUMBER() 的说明都是正确的,可以照用。

Claude Haiku 4.5▾

二次审核

我的答案

这个SQL查询和解释都是正确的。使用DENSE_RANK()配合CTE来找出每个部门工资排前三档的所有员工,正是解决这个问题的标准方案。工资相同的员工确实会获得相同排名,并一起列出来,符合题意。

逐项检验

CTE结构 — 正确。使用公共表表达式是最佳实践,避免了在WHERE中直接使用窗口函数的语法错误。

DENSE_RANK()的选择 — 正确。根据datadank.com的详细对比,当要求"工资排前三档"(即所有位列前三工资水平的员工)时,DENSE_RANK()正是应该使用的函数。它不会因为并列而跳过排名。

PARTITION BY department_id — 正确。确保了排名在每个部门内独立计算,不会混淆跨部门数据。

ORDER BY salary DESC — 正确。从高到低排序工资。

WHERE salary_rank <= 3 — 正确。过滤条件放在CTE外部,符合SQL执行顺序(窗口函数在WHERE之后计算)。

对三个排名函数的对比解释 — 完全正确。特别是对DENSE_RANK()的说明"不会跳过下一个排名"很准确。例如根据mentras.net的示例,若有两个人并列第二名,DENSE_RANK()下一名是第三,而RANK()会跳到第四。

遗漏的内容

  • NULL处理:如果salary列有NULL值,查询会将其视为最低值并参与排名。如果需要排除NULL或改变其排序位置,应加WHERE salary IS NOT NULL或ORDER BY salary DESC NULLS LAST(取决于数据库方言)。

  • 各数据库兼容性:答案未提及窗口函数支持的版本。根据mentras.net,DENSE_RANK()在MySQL 8.0+、PostgreSQL、Oracle、SQL Server中支持,但MySQL 5.7不支持。

  • 结果示例:没有给出具体的示例数据和输出结果,可能不够直观(datadank.com和github.com都提供了这类示例)。

修正后的答案

原答案完全正确,无需修改SQL逻辑或核心解释。如果要更完善,可在"解释"部分补充:

注意:

  • 如果salary列包含NULL值,可在WHERE中加入salary IS NOT NULL进行过滤。
  • 此查询支持MySQL 8.0及以上版本、PostgreSQL、Oracle和SQL Server等现代数据库。
  • 若有多个员工并列第三工资档位,他们会全部出现在结果中(这正是DENSE_RANK()的特点)。

它查阅的网页:Top N per Group in SQL: Top 3 Salaries per Dept | DataDank · 找出每个部门工资排名前 3 的员工。(分组取 top N) · SQL · Mentra · Mentra · 00185-department-top-three-salaries.sql · SQL Detective Mode: Using DENSE_RANK to Identify Top Earners by Department · 185. Department Top Three Salaries | leetcode SQL | by Data Science Wallah | Medium

轮到你了

要照着做之前,先查一遍。

把 ChatGPT、Claude、Gemini 或任何 AI 的回答贴进来,另外两家 AI 逐条查,告诉你哪里错了。

开始核对 安装 Chrome 插件

装上后,ChatGPT、Claude、Gemini 的每条回答下面都有一个“核对”按钮。

更多核对示例