背景
项目中根据业务需求写了一个group by的sql语句去查询数据,但是在执行过程中出现了一个问题,具体如下:
Caused by: java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'bus.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
看到这个错误的日志,猜测应该是sql_mode设置有问题,因此就去搜索了一下sql_mode相关的资料,发现不同的mysql版本,其默认的sql_mode是不一样的。就目前项目中比较常用的两个版本5.7和8.0来看,具体区别如下:
5.7:sql_mode="ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION"
8.0:sql_mode="ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION"
8.0比5.7少了一个NO_AUTO_CREATE_USER的设置
解释一下: ONLY_FULL_FROUP_BY,表示select后面的字段中只能出现分组列和聚合列;
STRICT_TRANS_TABLES,这个是针对insert操作而言的,单个insert操作,如果是innodb类型的表,插入数据与字段类型不兼容,则insert操作失败并回滚;如果是myisam类型表单行插入出现上述问题,则insert操作失败并回滚,批量插入多行,如果插入数据的第一行内容与字段类型不兼容,则insert操作失败并回滚,如果插入数据的第一行内容与字段类型兼容,但后续的数据行存在不兼容的情况,则兼容的数据正常插入,不兼容的数据会转换成符合字段类型的格式再插入,不会中断和回滚;
NO_ZERO_IN_DATE,这就是字面意思,在严格模式下,不允许月份和日期为零;
NO_ZERO_DATE,在严格模式下,不允许插入0日期;
ERROR_FOR_DIVISION_BY_ZERO,在严格模式下,不允许在字段中插入除数为0的运算值,否则会直接报错,但是直接计算除数为0的运算,返回null,给出警告warning;
NO_AUTO_CREATE_USER,禁止GRANT创建密码为空的用户;
NO_ENGINE_SUBSTITUTION,这个主要是针对存储引擎而言的,如果需要的存储引擎被禁用或未编译,那么抛出错误,不设置此值时,用默认的存储引擎替代,并抛出一个异常。
解决方式
看了sql语句没有问题,然后报文章开头展示的错误,于是分析应该是不同mysql版本sql_mode的问题, 于是去查看了一下mysql的版本,是8.0的版本,
(1)找到my.cnf,将sql_mode 设置为:
sql_mode="STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION"
重启mysql,错误解除。
(2)用docker方式安装mysql 5.7版本
启动容器后,执行含有group by的语句,还是报错,于是也去对应的地方修改sql_mode:
docker exec -it mysql bash
vi /etc/mysql/mysql.conf.d/mysqld.cnf
设置sql_mode="STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION"
重启mysql容器,sudo docker restart mysql,错误解除
(3)docker方式安装mysql 8.0版本
启动容器后,执行这条查询语句,不出所料,于是也去对应的地方修改sql_mode:
docker exec -it mysql bash
vi /etc/mysql/my.cnf
设置sql_mode="STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION"
重启mysql容器,sudo docker restart mysql,错误解除
结论
通过几个版本的验证,再回头看这条select语句,原来是查询字段中有的字段不在group by后的列中,搜索了资料说mysql版本5.7之后都需要修改一下sql_mode,于是尝试了三种解决方案,做了验证。同时,也发现,不同版本的mysql,其my.cnf路径不一样,名称也会不一样,所以修改的时候还需要找到对应的文件,切忌死搬硬套。