查询各国感染率时SQL报1055:SELECT字段不在GROUP BY子句
报错根因
MySQL 开启sql_mode=only_full_group_by模式时,强制要求SELECT列表中的非聚合列必须全部包含在GROUP BY子句中,且列之间要满足函数依赖关系。
你当前执行的SQL中,SELECT子句查询了非聚合列date,但GROUP BY仅按location, population分组:同一个国家、同一人口基数的分组下会对应多条不同日期的记录,SQL引擎无法确定需要返回哪条记录对应的date值,因此抛出1055错误。
排查解决方法
根据你的业务需求(对比人口基数下的各国最高感染率),有两类解决方案,优先推荐修正SQL逻辑的方案,不建议随意关闭SQL模式校验。
方案1:匹配业务需求修正SQL(推荐)
不要直接把date字段加到GROUP BY中——那样会变成按「国家+人口+日期」分组,统计结果是每日感染率,无法拿到国家维度的历史最高感染率数据,分两种需求场景写SQL:
- 场景1:不需要展示最高感染率对应的日期,只需要国家维度的统计值
直接删除SELECT列表中的date字段即可,修改后SQL如下:
SELECT location, population, MAX(total_cases) AS HighestInfectionCount, MAX((total_cases/population))*100 AS PercentPopulationInfected FROM coviddeaths GROUP BY location, population ORDER BY PercentPopulationInfected;
- 场景2:需要同时展示各国达到最高感染率的对应日期
先通过子查询统计每个国家的最高感染率,再关联原表匹配到对应日期的记录,SQL如下:
SELECT cd.location, cd.date, cd.population, cd.total_cases AS HighestInfectionCount, (cd.total_cases/cd.population)*100 AS PercentPopulationInfected FROM coviddeaths cd INNER JOIN ( SELECT location, population, MAX(total_cases/population) AS max_infect_rate FROM coviddeaths GROUP BY location, population ) t ON cd.location = t.location AND cd.population = t.population AND (cd.total_cases/cd.population) = t.max_infect_rate ORDER BY PercentPopulationInfected;
方案2:调整SQL模式关闭ONLY_FULL_GROUP_BY校验(不推荐生产环境使用)
如果仅做临时调试,可关闭该模式绕过校验,但同分组下的非聚合列会随机返回分组内某条记录的值,无法保证数据准确性:
- 先查询当前SQL模式配置,执行命令:
SELECT @@sql_mode; - 复制返回的配置值,删除其中的
ONLY_FULL_GROUP_BY字段,重新设置会话级别的SQL模式,示例:SET sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
注意:上述设置仅对当前数据库连接生效,连接断开后会恢复原配置。如果需要全局永久生效,需要修改MySQL配置文件
my.cnf中的sql_mode配置项,重启数据库后生效。
内容的提问来源于stack exchange,提问作者Eric w
相关产品推荐
相关产品推荐

