一、错误原因分析
出现这个问题是因为,对于group by操作,如果在select中的列,没有在group by中出现,那么这个sql是不合法的,因为列不在group by从句中。
也就是说如果我分组查询,比如我表里有三个字段 id、name、type,我根据type分组查询,那么结果集里就不能包含name字段。
# 错误查询 会出现this is incompatible with sql_mode=only_full_group_by select `name`,`type` from user_01 group by `type`; # 正确查询 不会出现问题 select `type` from user_01 group by `type`;
二、原理分析&解决方案分析
- 要想解决这个问题首先要知道mysql的 sql_mode 是什么,sql_mode 是个很容易被忽视的变量,sql_mode 是规范一些数据库校验规则,比如这里出现的sql_mode=only_full_group_by 问题,only_full_group_by 就是一个校验规则,会规定分组查询结果集不能有group by中没有出现的列。
- 这个错误发生在mysql 5.7.5 版本及以上版本会出现的问题,mysql 5.7.5版本以上默认的 sql_mode 是包含 only_full_group_by ,这个配置严格执行了"sql92标准",很多从5.6升级到5.7时,为了语法兼容,大部分都会选择调整sql_mode,使其保持跟5.6一致,为了尽量兼容程序。
有两种解决逻辑:
- 第一种:就是顺应这个规则,别在group by是返回额外的列,当然,竟然sql都这样写了肯定是需要额外的列了,我们看第二种方法
- 第二种:放开限制就行,将sql_mode 中的 only_full_group_by 剔除就行。
二、临时解决(不需要重启mysql,适配所有版本和任意安装方式的mysql,重启mysql后会失效)
临时解决这个问题可以不用重启mysql服务,,通过 set global 命令直接改就行。
1、查看当前 sql_mode (我这里mysql的版本是8.0,其它版本也是一样的做法)
登录数据库执行下面命令可以看到当前包含的 sql_mode ,不同版本mysql结果可能不同,但是我们的问题是因为 only_full_group_by 引起的,我们看看里面是否有这个。
show variables like "sql_mode";
这里可以看到,我的 sql_mode 中第一个就是 only_full_group_by
only_full_group_by,strict_trans_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution
2、临时修改 sql_mode
将刚刚查询到的 sql_mode 删除里面的 only_full_group_by,重新设置到系统配置中即可。
# 修改全局配置 sql_mode set global sql_mode='strict_trans_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution'; # 修改session配置 sql_mode set session sql_mode='strict_trans_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution';
ps:如果是使用代码(jdbc)连接的数据库,修改完成之后最好重启一下代码服务,mysql服务不用重启,如果不重启可能还是会出现该问题,重启后生效。
三、彻底解决(需要重启mysql才会生效)
要彻底解决这个问题就是将临时解决方案中的 sql_mode 通过配置文件设置即可,建议是和临时方案一起使用,先通过临时方案让业务服务可用,然后在配置文件也配置 sql_mode 下一次mysql重启后生效。
1、window 配置 sql_mode
window 上的 mysql 配置文件默认是在 c:\program files\mysql\mysql server 8.0\my-default.ini,打开这个 my-default.ini 文件找到[mysql],在 [mysqld] 下设置 sql_mode ,将通过show variables like "sql_mode";
查询出来的 sql_mode 剔除 only_full_group_by 即可。
sql_mode='strict_trans_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution'
重启mysql:
- 打开windows的服务管理器,可以通过快捷键win+r打开运行窗口,输入services.msc后按回车键。
- 找到mysql服务,服务名称可能会叫mysqlxx(xx是版本信息),右键点击,选择停止服务。
- 等待mysql服务停止后,再右键点击mysql服务,选择启动服务。
- 重启mysql服务后,可以通过以下命令检查mysql是否已正常运行
重启好在mysql客户端执行show variables like "sql_mode";
查询 sql_mode 是否已经改变。
2、linux 配置 sql_mode
linux 上的 mysql 配置文件默认是在 /etc/mysql/my.cnf,打开这个 my.cnf 文件找到[mysql],在 [mysqld] 下设置 sql_mode ,将通过show variables like "sql_mode";
查询出来的 sql_mode 剔除 only_full_group_by 即可。
# 打开/etc/mysql/my.cnf 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:service mysqld restart
或 service mysql restart
3、docker 配置 sql_mode
docker 安装的 linux版本mysql 配置文件默认是在也是容器的 /etc/mysql/my.cnf 中,不过有点区别的是我们一般去直接改容器中的配置文件,而是会将额外配置文件路径挂载出来,而且容器中是没有 vi 这种工具不方便直接改配置,这里会对有做挂载和没有做挂载的修改方式都说做说明。
使用docker安装的mysql的额外配置文件是在容器的 /etc/mysql/conf.d 目录的,mysql会读取这个目录下所以以 .cnf 结尾的文件,如果有对这个目录做挂载最好,如果没有做挂载也可用通过宿主机copy到容器内部。
1、配置文件准备
我的配置文件目录是挂载到了 /home/docker/mysql/conf.d,自己根据实际情况调整。
# 创建一个配置文件 vi /home/docker/mysql/conf.d/mysql.cnf
将下面的内容写入 mysql.cnf 保存即可
[mysqld] sql_mode='strict_trans_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution'
2、如果没有做挂载需要将这个配置文件拷贝到容器内(有做挂载跳过)
docker cp /home/docker/mysql/conf.d/mysql.cnf 容器id:/etc/mysql/conf.d/mysql.cnf
3、重启容器
docker restart 容器id/容器名称
4、检验是否修改成功
# 进入容器 docker exec -it 容器id/容器名称 /bin/bash # 连接mysql mysql -h127.0.0.1 -uroot -p # 查看sql_mode是否被修改成功 show variables like "sql_mode";
到此这篇关于解决mysql this is incompatible with sql_mode=only_full_group_by 问题的文章就介绍到这了,更多相关mysql incompatible with内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论