能,但仅限mysql、postgresql、sql server等部分数据库支持group by 1(按select列表第1字段分组),oracle不支持;因其易引发维护风险、逻辑隐晦、重构易错,强烈不建议生产环境使用,应优先采用明确的列名或别名。

GROUP BY 能不能用 SELECT 字段序号(比如 GROUP BY 1)?
能,但仅限部分数据库,且强烈不建议在生产 SQL 中使用。
MySQL、PostgreSQL、SQL Server 都支持 GROUP BY 1 这种写法——它表示“按 SELECT 列表中第 1 个字段分组”。但这只是语法糖,背后不改变语义,反而容易埋坑。
-
MySQL:默认允许
GROUP BY 1,但前提是该序号对应的是一个确定的、非表达式的列(比如SELECT a, b + c FROM t中GROUP BY 2会报错,因为b + c不是原始列) - PostgreSQL:支持,但要求序号指向的必须是简单列名或别名,不能是复杂表达式
-
SQL Server:支持,但只认 SELECT 列表中“裸列名”或“明确别名”,比如
SELECT name AS n FROM t GROUP BY 1可行,SELECT UPPER(name) GROUP BY 1会失败 -
Oracle:不支持字段序号,直接报错
ORA-00979: not a GROUP BY expression
为什么 GROUP BY 1 容易出错?
问题不在语法能否通过,而在于可维护性和歧义风险。
- 当 SELECT 列表被重构(比如加了新字段、调换顺序),
GROUP BY 1指向的字段就悄悄变了,查询逻辑可能完全偏离预期,但数据库不报错 - 嵌套查询或视图中,外层
GROUP BY 1实际引用的是内层 SELECT 的第 1 列,层级一多根本没法快速判断分组依据 - 和
HAVING或ORDER BY混用时,三者都用序号容易互相干扰,比如ORDER BY 1和GROUP BY 1指的未必是同一列 - 团队协作时,没人愿意花时间数“第几个字段”,尤其 SELECT 有 8 个字段+别名时
替代方案:怎么写更安全?
用字段名或别名,而不是数字序号。哪怕多打几个字,也比后期 debug 半天强。
- 优先用原始列名:
GROUP BY department,而不是GROUP BY 1(即使SELECT department, ...) - 如果用了别名,就用别名:
SELECT dept_name AS department, COUNT(*) FROM t GROUP BY department是合法且清晰的 - 多字段分组时,别省略——
GROUP BY department, hire_year比GROUP BY 1, 2明确十倍 - 在 MySQL 中,如果启用了
ONLY_FULL_GROUP_BY(默认开启),GROUP BY 1仍需确保该序号列是确定性、非聚合的,否则照样报错
真正麻烦的不是写 GROUP BY department 多敲三个字母,而是某天凌晨三点发现报表数据对不上,追查两小时才发现有人把 SELECT 顺序改了,而 GROUP BY 2 还静静躺在那儿。










