执行GROUP BY查询各部门最高薪员工时为何触发ERROR 1055?
先明确你的场景:
你有一个employees表,结构和数据如下:
表结构
CREATE TABLE employees(id int AUTO_INCREMENT PRIMARY KEY, emp_name VARCHAR(10), dept VARCHAR(10), salary DECIMAL(8,2));
插入数据
INSERT INTO employees (dept,emp_name,salary) VALUES('Engg','Sam',1000); INSERT INTO employees (dept,emp_name,salary) VALUES('Engg','Smith',2000); INSERT INTO employees (dept,emp_name,salary) VALUES('HR','Denis',1500); INSERT INTO employees (dept,emp_name,salary) VALUES('HR','Danny',3000); INSERT INTO employees (dept,emp_name,salary) VALUES('IT','David',2000); INSERT INTO employees (dept,emp_name,salary) VALUES('IT','John',3000); INSERT INTO employees (dept,emp_name,salary) VALUES('Sales','Ravi',4000); INSERT INTO employees (dept,emp_name,salary) VALUES('Sales','Bob',6000); INSERT INTO employees (dept,emp_name,salary) VALUES('HR','Rick',4500); INSERT INTO employees (dept,emp_name,salary) VALUES('IT','Mathew',2500);
表数据
+----+----------+-------+---------+ | id | emp_name | dept | salary | +----+----------+-------+---------+ | 1 | Sam | Engg | 1000.00 | | 2 | Smith | Engg | 2000.00 | | 3 | Denis | HR | 1500.00 | | 4 | Danny | HR | 3000.00 | | 5 | David | IT | 2000.00 | | 6 | John | IT | 3000.00 | | 7 | Ravi | Sales | 4000.00 | | 8 | Bob | Sales | 6000.00 | | 9 | Rick | HR | 4500.00 | | 10 | Mathew | IT | 2500.00 | +----+----------+-------+---------+
你执行了这条SQL想查询各部门薪资最高的员工:
SELECT id, emp_name, salary, dept FROM employees GROUP BY dept;
结果触发了错误:
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test_db.employees.ID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
错误原因详解
这个错误的核心是MySQL的only_full_group_by SQL模式在严格约束你的查询逻辑,它是SQL标准规定的行为,MySQL从5.7版本开始默认启用了这个模式。
1. only_full_group_by的核心规则
简单来说,这个模式要求:
- SELECT列表里的每一列,要么是GROUP BY子句中明确列出的列,要么是被聚合函数(比如MAX()、MIN()、COUNT())包裹的列
- 唯一例外:如果GROUP BY的列是表的主键(或唯一键,能唯一标识每一行),那么SELECT里的其他列可以不用在GROUP BY里——因为主键确定后,其他列的值也就唯一确定了,属于功能依赖关系。
2. 你的SQL直接违反了规则
看你的查询:SELECT id, emp_name, salary, dept FROM employees GROUP BY dept;
- GROUP BY的只有
dept列,但dept不是唯一键(每个部门对应多个员工) - SELECT里的
id、emp_name、salary既不在GROUP BY里,也没有用聚合函数包裹
举个具体例子:HR部门有3个员工,他们的id分别是3、4、9,薪资分别是1500、3000、4500。当你按dept分组后,MySQL根本不知道要返回这三个员工中的哪一个的id、姓名和薪资——这种模糊的查询在严格模式下是不被允许的,所以直接抛出了错误。
实现需求的正确写法
你真正的需求是查询各部门中薪资最高的员工,可以用以下两种方式实现:
方法1:子查询关联(兼容所有MySQL版本)
先找出每个部门的最高薪资,再关联原表找到对应的员工:
SELECT e.id, e.emp_name, e.salary, e.dept FROM employees e INNER JOIN ( -- 子查询获取各部门最高薪资 SELECT dept, MAX(salary) AS max_salary FROM employees GROUP BY dept ) dept_max ON e.dept = dept_max.dept AND e.salary = dept_max.max_salary;
方法2:窗口函数(MySQL 8.0及以上版本推荐)
用RANK()窗口函数给每个部门的员工按薪资降序排名,然后取排名为1的员工:
SELECT id, emp_name, salary, dept FROM ( SELECT *, -- 按部门分区,薪资降序排名 RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS salary_rank FROM employees ) ranked_emps WHERE salary_rank = 1;
这两种写法都能正确返回各部门薪资最高的员工,同时符合only_full_group_by的规则。
内容的提问来源于stack exchange,提问作者Manikandan

