SQL中为何SELECT语句的所有非聚合列需纳入GROUP BY子句?
为什么GROUP BY子句必须包含所有SELECT中的非聚合列?
使用聚合函数(COUNT()、用于条件逻辑的CASE)时,GROUP BY子句应包含所有被选中的非聚合列
这个规则的核心逻辑很直白:GROUP BY的作用是把数据按指定字段拆分成若干分组,每组最终只会输出一行聚合结果。如果SELECT里列了某个非聚合字段(也就是没被COUNT/SUM/MAX这类聚合函数包裹的字段),但没把它放进GROUP BY,数据库根本没法确定该从这个分组的多行数据里选哪一行的字段值返回——同一个分组里这个字段可能有好几个不同的值,数据库没有默认的“选哪个”规则,只能报错要求你明确分组依据。
拿你给出的例子具体说明:
错误查询示例
select e.first_name, e.last_name, count(o.order_id) as num_orders, (case when shipped_date <= required_date then 'On Time' else 'Late' end) as shipped from employees e join orders o on e.employee_id = o.employee_id group by e.employee_id order by last_name, first_name, num_orders desc
这里GROUP BY只指定了e.employee_id,但SELECT里的first_name、last_name、shipped都是非聚合列。虽然employee_id是员工表主键,和first_name、last_name一一对应,但shipped是根据订单发货状态生成的——同一个员工可能既有按时发货的订单,也有延迟的,按employee_id分组后,这个组里shipped会有两个不同的值,数据库无法确定返回哪一个,因此这个查询不合法。
正确查询示例
select e.first_name, e.last_name, count(o.order_id) as num_orders, (case when shipped_date <= required_date then 'On Time' else 'Late' end) as shipped from employees e join orders o on e.employee_id = o.employee_id group by e.first_name, e.last_name, shipped order by last_name, first_name, num_orders desc
这个查询把所有SELECT里的非聚合列都放进了GROUP BY:按员工姓名+发货状态分组,这样每个分组里的first_name、last_name、shipped值完全一致,数据库可以明确返回这些值,再配合count(o.order_id)统计每组的订单数量,结果清晰且符合逻辑。
内容的提问来源于stack exchange,提问作者user321627
相关产品推荐
相关产品推荐

