SQL中GROUP BY p是否不合理?如何改写获取产品平均评分的查询?
你的SQL查询问题解析
首先说结论:你的查询在不同数据库里表现不一样,大概率会报错,GROUP BY p这种写法不通用也不规范。
为什么GROUP BY p有问题?
- 多数主流数据库(比如PostgreSQL、开启了
ONLY_FULL_GROUP_BY的MySQL)不支持直接按整个表别名分组。SQL标准要求,SELECT里出现的非聚合字段(也就是p.*里的每一列),必须都出现在GROUP BY子句里,或者被聚合函数包裹。你写GROUP BY p相当于没明确指定分组的字段,数据库不知道怎么处理。 - 就算某些数据库允许这种写法,也可能出现逻辑错误——比如如果product表存在重复行(虽然主键不会重复,但万一其他字段有重复场景),分组结果可能不符合预期。
要返回全部产品详情,正确的分组方式是什么?
有两种靠谱的写法:
明确列出所有product字段
把p.*里的每一列都写到GROUP BY里,比如:SELECT p.id, p.name, p.price, p.description, -- 列出product表所有字段 AVG(r.rating) AS avg_rating FROM product p LEFT JOIN reviews r ON r.productId = p.id GROUP BY p.id, p.name, p.price, p.description -- 和SELECT里的非聚合字段一一对应这种写法符合所有数据库的SQL标准,绝对不会出错,就是字段多的时候写起来麻烦。
按主键分组(推荐)
如果product表有主键(比如id),那在MySQL 8.0+、PostgreSQL 10+这些新版本数据库里,只需要按主键分组就行。因为主键唯一标识一条产品记录,数据库会自动关联其他字段,不需要全部列出来:SELECT p.*, AVG(r.rating) AS avg_rating FROM product p LEFT JOIN reviews r ON r.productId = p.id GROUP BY p.id这种写法简洁又规范,是最优解。
额外优化建议
没有评论的产品,avg_rating会返回NULL,如果想让它显示0更友好,可以用COALESCE函数处理:
SELECT p.*, COALESCE(AVG(r.rating), 0) AS avg_rating FROM product p LEFT JOIN reviews r ON r.productId = p.id GROUP BY p.id
内容的提问来源于stack exchange,提问作者managerit017
相关产品推荐
相关产品推荐

