select 在聚合查询中直接报错,因sql标准强制要求非聚合字段必须出现在group by子句中;而select 无差别引入所有字段,数据库无法判定哪些需分组、哪些需聚合,解析阶段即拒绝执行。

SQL 聚合查询中写 SELECT * 是语法错误,根本执行不了——数据库会直接报错,不是“慢”或“有风险”,而是“不合法”。
为什么 SELECT * 在聚合查询里直接报错
聚合查询(含 GROUP BY、MIN、COUNT 等)要求:所有非聚合字段必须出现在 GROUP BY 子句中。而 SELECT * 会把表所有字段无差别拉进来,数据库无法判断哪些该分组、哪些该聚合。
- MySQL 8.0+ 报错:
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column - PostgreSQL 报错:
column "xxx" must appear in the GROUP BY clause or be used in an aggregate function - SQL Server 报错:
is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
这不是配置问题,是 SQL 标准强制约束。引擎在解析阶段就拒绝,连执行计划都不会生成。
SELECT * 和聚合函数混用的常见误写场景
开发者常误以为 “先查全量再聚合” 可行,比如想看每个部门的员工数和全部员工信息,写出:
SELECT *, COUNT(*) FROM employees GROUP BY dept_id;
这在任何主流数据库中都非法。真正可运行的等价逻辑只有两种:
- 用窗口函数:
SELECT *, COUNT(*) OVER (PARTITION BY dept_id) AS cnt FROM employees - 用子查询/JOIN 拆开:
SELECT e.*, t.cnt FROM employees e JOIN (SELECT dept_id, COUNT(*) cnt FROM employees GROUP BY dept_id) t ON e.dept_id = t.dept_id
注意:COUNT(*) 里的 * 是特例,它只表示“计行数”,和 SELECT * 的语义完全不同,不可类比。
为什么有人觉得它“能跑”?——其实是没触发聚合逻辑
以下情况看似用了 SELECT * 又没报错,但其实根本没走聚合:
- 漏写
GROUP BY,实际变成普通查询(如 MySQL 5.7 兼容模式下可能允许,但结果不可靠) - 表为空,或聚合函数被优化器提前剪枝(如
SELECT *, MAX(id) FROM empty_table可能返回空结果,但不是“聚合成功”) - 用视图封装了聚合逻辑,外部查视图时写
SELECT *—— 此时*展开的是视图定义的列,不是原表列,已脱离原始聚合上下文
这类“侥幸通过”的语句极难维护,换数据库版本或参数就失效。
最易被忽略的一点:聚合查询的字段意图是明确的——你要分组依据、要统计值、要展示维度。用 * 直接抹掉了这种语义表达,让 SQL 从“声明式逻辑”退化成“碰运气取数”。真要查多字段,就老老实实列出来,让数据库和人都看得懂你在分什么、聚什么、展什么。











