GROUP BY 1 不被推荐,因其依赖 SELECT 字段顺序,降低可维护性、易出错且跨库不可移植;虽语法合法,但在严格模式下仍触发非聚合列未分组报错,且无法规避 SQL 标准校验。

GROUP BY 1 这种写法在生产环境里不被推荐,根本原因不是它语法错误,而是它让 SQL 失去可维护性、易出错且跨数据库不可移植。
GROUP BY 1 是什么?它为什么能跑通?
它表示按 SELECT 列表中第 1 个字段分组。例如:SELECT user_id, name, COUNT(*) FROM users GROUP BY 1,等价于 GROUP BY user_id。MySQL、PostgreSQL 等多数引擎都支持这种位置引用——但仅限于简单查询。
- 它依赖 SELECT 字段顺序,一旦前面加字段、删字段、改字段顺序(比如重构时把
name提前),GROUP BY 1就悄悄指向了别的列 - 它不体现业务语义,别人读不到“为什么要按 user_id 分组”,只看到“按第一个字段”
- 某些 ORM 或报表工具生成的动态 SQL 中,字段顺序可能因参数变化而波动,
GROUP BY 1就会失效
MySQL 5.7+ 和 KingbaseES V8 下的报错更直接暴露问题
当开启 ONLY_FULL_GROUP_BY 模式(MySQL 默认启用)或使用 KingbaseES V8 这类严格遵循 SQL 标准的数据库时,GROUP BY 1 并不能绕过校验逻辑——它仍要检查 SELECT 列是否满足“非聚合列必须显式出现在 GROUP BY 中”的规则。此时若你写了 SELECT user_id, name, COUNT(*) GROUP BY 1,name 既没聚合也没出现在 GROUP BY 子句里(哪怕 1 指向 user_id),就会报错:Expression #2 of SELECT list is not in GROUP BY clause。
- 错误信息里说的“#2”就是
name,不是1所指的列——说明校验发生在语义解析后,而非字符串替换阶段 - 也就是说,
GROUP BY 1不是“魔法开关”,它不改变标准合规性判断 - PostgreSQL 更彻底:连
GROUP BY 1都允许,但只要 SELECT 出现未聚合也未分组的列,立刻拒绝执行
用列名替代 GROUP BY 1 的实操要点
把 GROUP BY 1 改成明确列名,不只是风格问题,是防止线上故障的最小成本动作。
- 优先用业务主键或自然键:如
GROUP BY user_id,而不是GROUP BY id(如果表有多个id字段) - 多列分组时,顺序无关紧要,但必须完整列出所有非聚合列:如
SELECT dept, role, AVG(salary) GROUP BY dept, role - 如果确实需要“取某组任意一行的某个字段”,用
ANY_VALUE(name)(MySQL)或STRING_AGG(name, ',')(PostgreSQL),而不是靠GROUP BY 1蒙混过关 - 对视图或 CTE 中的查询,尤其不能用位置编号——字段别名、计算列会让位置关系完全不可靠
真正容易被忽略的点在于:GROUP BY 1 在单表简单查询里几乎不会出事,但只要涉及 JOIN、子查询、字段重排、ORM 动态拼接,它就变成一个静默的定时炸弹。修复成本远低于排查一次凌晨三点的报表数据错乱。

















