必须将所有非聚合字段显式写入GROUP BY子句,否则主流数据库(PostgreSQL/SQL Server/Oracle)会报错,MySQL 5.7+启用ONLY_FULL_GROUP_BY后行为一致;语义模糊的查询不可靠,应使用窗口函数等正确方案。
可以,但必须满足严格条件——不是“能不能写”,而是“写了会不会执行成功”或“结果是否可靠”。不同数据库行为差异极大,硬写不加聚合函数的 GROUP BY,轻则报错,重则返回随机值,线上出问题很难追溯。
典型错误信息:column "name" must appear in the GROUP BY clause or be used in an aggregate function。这不是兼容性问题,是 SQL 标准强制校验:数据库拒绝执行语义模糊的查询。
GROUP BY 子句中user_id 和 user_name 是主从关系),标准数据库也要求你写全:GROUP BY user_id, user_name
MySQL 5.7 启用 sql_mode=ONLY_FULL_GROUP_BY 后,行为和其他主流数据库一致。若关闭该模式,虽然能跑通,但 SELECT user_id, name FROM t GROUP BY user_id 中的 name 返回的是“某一行的值”,不可预测、不可复现。
ANY_VALUE(name) 是唯一明确表达“我要随便取一个”的方式,但仅 MySQL 支持,且不保证跨查询稳定MAX(name) 或 MIN(name) 看似可行,但按字典序取值,和业务语义无关(比如不是最新名、也不是注册名)GROUP_CONCAT(name) 拼接多值时,注意默认长度限制(group_concat_max_len),超长会被截断例如按 order_id 分组,想取每单最新的 status 和 updated_at,写 SELECT order_id, MAX(updated_at), ANY_VALUE(status) 是错的——ANY_VALUE(status) 不保证和 MAX(updated_at) 来自同一行。
ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC),再过滤 rn = 1
LATERAL(PostgreSQL)、QUALIFY(BigQuery / Snowflake)GROUP BY 的方案,在数据变更频繁或存在时间戳/状态更新时,几乎必然出错最易被忽略的一点:即使语法通过,只要 SELECT 列里有非聚合字段又没放进 GROUP BY,就说明你还没想清楚“这一行结果到底代表什么”。数据库报错不是刁难,是在逼你把业务语义写清楚。