SQL如何获取分组内的最大值_MAX函数与GROUP BY结合

4次阅读

GROUP BY 后直接用 MAX() 只返回每组最大值,不保留对应行其他字段;若需完整记录,MySQL 8.0+ 推荐用 ROW_NUMBER() 窗口函数,老版本可用子查询或 LEFT JOIN。

SQL 如何获取分组内的最大值_MAX 函数与 GROUP BY 结合

GROUP BY 后直接用 MAX() 是最常用但容易误解的写法

MAX() 和 GROUP BY 一起用,确实能拿到每组的最大值,但它只返回聚合结果,不保留对应那行的其他字段。比如你查 SELECT dept, MAX(salary) FROM emp GROUP BY dept,能知道每个部门最高工资是多少,但不知道是谁拿的、入职时间、职位——这些信息全丢了。

常见错误现象:SELECT dept, name, MAX(salary) FROM emp GROUP BY dept 在 MySQL 5.7+ 默认会报错(sql_mode=only_full_group_by 开启时),因为 name 不在 GROUP BY 里,也不是聚合函数结果,数据库没法确定该取哪一行的 name

  • 如果你只要最大值本身,MAX() + GROUP BY 完全够用
  • 如果还要整行数据(比如“工资最高的员工完整信息”),就不能只靠 MAX(),得换思路
  • MySQL 8.0+、PostgreSQL、SQL Server 支持窗口函数,是更稳妥的选择

想查“每组中 salary 最大的那条完整记录”,用窗口函数 ROW_NUMBER()

核心思路:先按分组排序,给每组内的行编号,再筛出序号为 1 的行。比子查询或 JOIN 更直观,也避免了 MAX() + 关联查询时可能的多行匹配问题(比如两个员工工资并列最高)。

实操建议:

  • ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) 给每组按工资降序编号
  • 外层套一层查询,过滤 rn = 1 即可拿到每组“第一个最高工资员工”
  • 如果要包含并列情况(即所有最高工资者都返回),改用 RANK()DENSE_RANK()

示例(MySQL 8.0+):

SELECT dept, name, salary FROM (SELECT dept, name, salary,          ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn   FROM emp ) t WHERE rn = 1;

兼容老版本 MySQL(5.7 及以下)只能靠相关子查询或 LEFT JOIN

窗口函数不可用时,最容易想到的是子查询:WHERE salary = (SELECT MAX(salary) FROM emp e2 WHERE e2.dept = e1.dept)。但要注意:它会在每行都执行一次子查询,数据量大时性能明显下降;而且当存在并列最大值时,它会正确返回所有并列者——这点反而比 ROW_NUMBER() 更符合直觉。

另一个方案是自连接:LEFT JOIN emp e2 ON e1.dept = e2.dept AND e1.salary,逻辑是“找不到同部门更高工资的人”,就说明当前行是最高。这个写法在某些场景下执行计划更优,但可读性差,且容易漏掉 NULL 值处理。

  • 子查询方式简洁易懂,适合中小表;注意加 deptsalary 联合索引提升性能
  • JOIN 方式对大表可能更快,但必须确保 salary 字段非 NULL,否则 e1.salary 会让 NULL 行被过滤掉
  • 两种方式在有重复最大值时行为一致,都能返回全部并列记录

别忽略 NULL 和数据类型隐式转换带来的偏差

MAX() 对 NULL 值默认忽略,这通常没问题;但如果你的 salary 字段是字符串类型(比如存了“$5000”),MAX() 就会按字典序比较,导致“$900”>“$10000”。这种错误不会报错,但结果完全错乱。

  • 检查字段类型:用 DESCRIBE empSHOW COLUMNS FROM emp 确认 salary 是数值型(如 DECIMALINT
  • 如果数据里混了单位或符号,先清洗再计算,不要依赖 CAST()REPLACE() 在查询里硬转——影响索引使用和性能
  • ORDER BY 中用 NULLS LAST(PostgreSQL)或 IS NULL 排序(MySQL)来控制 NULL 的位置,尤其当你用 RANK() 时,NULL 可能被排第一

真正麻烦的不是语法怎么写,而是搞清你要的到底是“最大值”,还是“最大值所在行”,或是“所有并列最大值的行”——这三个需求对应三种完全不同的写法,选错一个,结果就偏了。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-22发表,共计1757字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources