mysql8的group by引起的异常:sql_mode=only_full_group_by

735 阅读2分钟

参考资料

mysql官网相关文档

发生的问题

当我写下如下sql进行分组查询时:

SELECT * FROM `table` GROUP BY update_time;

爆出如下错误:

> 1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'sentence. 'id' which is not functionally dependent on columns in GROUP BY clause;  this is incompatible with sql_mode=only_full_group_by

翻译的意思是:

SELECT列表的表达式#1不在groupby子句中,并且包含非聚合列的sentence。 'id'在功能上不依赖于GROUP BY子句中的列; 这与sql_mode=only_full_group_by不兼容

我理解的意思是:

如果想正常使用,需要GROUP BY后列表和select后列表保持一致,或者GROUP BY后跟个聚合列,比如主键。

发生的原因分析

mysql 5.7.5之后,实现了功能依赖检测,即默认开启sql_mode=only_full_group_by

官方原话该指令代表着:拒绝SELECT列表、HAVING条件或 ORDER BY列表引用非聚合列的查询,这些列既不在GROUP BY子句中命名,也不在功能上依赖于它们。

如果不遵守这个规则就可能会爆出此错误。具体看特性解析。

only_full_group_by特性解析

说明在这种模式下如何进行sql书写,以及该模式的优劣分析。

引用聚合列

# GROUP BY 引用聚合列id为条件分组,可以执行
SELECT * FROM `table` GROUP BY id;

引用非聚合列但限定单一结果

# GROUP BY 引用非聚合列 update_time
# 但是由于 WHERE 语句将查询结果限制为一条结果,可以执行,仅限一条结果
SELECT * FROM `table` WHERE id = 1 GROUP BY update_time;

any_value()

# 通过any_value()函数可以屏蔽某个字段被该模式的影响
SELECT ANY_VALUE(update_time) AS update_time FROM `table` GROUP BY update_time;

only_full_group_by模式优劣

官方话:如果禁用此模式,则服务器可以从每个组中自由选择任何值,因此除非它们相同,否则选择的值是不确定的,这可能不是您想要的。

个人理解:如果不使用此模式,分组后的每组“代表”可能会被选择成你不想要的那个代表,除非这组“代表”都相同,如果分组的“代表”被选择成你不想要的那个,你后序的操作也会受到影响。

个人感觉:貌似他的优点不是很大,而启用后,对于已经确定不会有影响的sql,又需要诸多额外操作以去除被这种模式带来的影响。但是个人学识尚浅,各位斟酌理解。

解决方案

关闭模式

去网上搜,一堆

遵守特性

参见特性解析,主要是any_value()