首先从一个无意中运行的例子讲起。数据表结构及数据如下(建表语句及插入语句就不提供了)。
看下面一段SQL语句及运行结果:
从这个结果我们可以发现两件事情。第一,这条查询语句中没有group by子句,select子句中的非聚合字段没有出现在group by子句中,这与我们一贯的认知不同。类似语法的SQL查询语句在hive中是报错的(在MySQL也有可能报错,后面会详细说)。第二,这从这条语句的执行结果可以看出,SQL查询语句中的聚合函数字段执行完成,而非聚合字段似乎返回了满足where条件的第一条记录的order_id的值。但该order_id对应的(original_value-discount)的值并不是我们所求的max结果。
下面来分析一为什么会出现这中情况及结果。
通常MySQL5.7及以上版本中sql_mode是默认设置了ONLY_FULL_GROUP_BY模式的。一旦设置了该模式,会将两类SQL查询语句判定为不合法,具体如下:
- 第1类,select子句、having子句、order by子句中的非聚合函数字段没有group by子句的查询语句。
- 第2类,select子句、having子句、order by子句中的非聚合函数字段与group by 子句中字段没有函数依赖(functional dependency)。
再来看上面那段SQL语句,没有group by子句,也就意味着select 子句中的非聚合函数字段order_id没有出现在group by子句中,也就不存在函数依赖关系。所以我们可以推测我的MySQL的sql_mode中没有设置ONLY_FULL_GROUP_BY模式。但是在MySQL 5.7及以上版本中,ONLY_FULL_GROUP_BY模式是默认开启的,而关掉该模式可以在my.ini文件中修改sql_mode参数。具体如下:
MySQL8.0中的若是没有my.ini文件,可以参考https://www.cnblogs.com/RayWang/p/9347874.html 。
接着在看在关闭了ONLY_FULL_GROUP_BY模式下,会如何处理在其开启状态下判定为不合法的两类SQL查询语句。
- 首先,非聚合字段没有出现在group by 子句中。
如果select子句中有未出现在group by子句中的普通字段,这是服务器或从每个组中随机选择一个值输出。
此时,上述SQL查询语句等价于如下代码:
- 其次,非聚合字与group by中的字段不存在函数依赖关系。
先来看看什么是函数依赖。MySQL函数依赖是指:X能够决定Y,即当X确定之后,Y也就确定了,则我们说Y函数依赖X。 以下面代码为例:
从对原始数据的分析中可以发现,order_id其实是表的主键,那自然当按order_id进行分组之后,就已经在每个分组内部完成了cust_id的分组。所以上述代是可以运行的。但是字段之间的函数依赖只能基于键,基于相等性及基于视图建立。其他情况,及时X唯一确定了一个Y,也不能算是函数依赖。如下:
在上述SQL代码中,一个city,只会对一个area,但仍然提示1055错误。
参考资料:
1. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
2. https://dev.mysql.com/doc/refman/5.7/en/group-by-functional-dependence.html