问题
MySQL5.7
以上版本,默认是开启了 only_full_group_by
模式的:
> select @@sql_mode
> select @@global.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
开启这个模式后,原先的 group by
语句就报错:
SELECT list is not in GROUP BY clause and contains nonaggregated column 'test' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
原因
MySQL
在低版本(5.7.x
以下)中允许 select
后面的非聚合列不出现在 group by
中。以下sql
在低版本中是可以运行的,但是在5.7及以上版本会报错:
select name, age, count(name) from student group by age
因为在SQL
标准中,出现在select target list
中,并且没有出现在聚集函数中的表达式必须出现在group by
子句中:
order by后面的列必须是在
select
中存在select、having或order by后面存在的非聚合列必须全部在group by中存在
而没有遵循原则的sql
会被认为是不合法的sql
,如SQLServer
、Oracle
、PostgreSql
都不支持select target list
中出现语义不明确的列,MySQL 5.7
开始修正,即ONLY_FULL_GROUP_BY
语义。
解决
开启 only_full_group_by
,group by
将变成和 distinct
一样,只能获取受到其影响的字段信息,无法和其他未受其影响的字段共存,这样,group by
的功能将变得十分狭窄。
-
保持
only_full_group_by
模式开启MySQL
提供了any_value(field)
函数允许非分组字段的出现(和关闭 only_full_group_by 模式有相同效果)。select any_value(name), age, count(name) from student group by age
-
关闭only_full_group_by
-
当前会话关闭:
只在当前会话生效,关闭当前会话就失效。
> select @@sql_mode
复制查询出来的值,去除
only_full_group_by
,再设置回去:> set sql_mod='去除only_full_group_by后的值'
比如:在
navicat
中当前窗口执行,在当前窗口生效,新开窗口失效。 -
当前服务关闭:
当前服务生效,重启服务失效(该方法,我设置好像不生效?)
> select @@global.sql_mode
复制查询出来的值,去除
only_full_group_by
,再设置回去:> set global sql_mod='去除only_full_group_by后的值'
-
修改MySQL程序配置:
需重启
MySQL
生效。永久生效,但生产环境上是禁止重启MySQL
服务。MySQL
配置文件my.conf
目录:# mysql --help | grep 'my.cnf' order of preference, my.cnf, $MYSQL_TCP_PORT, /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
从左到右优先级,后者覆盖前者重复参数。
添加:
[mysqld] sql_mode=去除only_full_group_by后的值
-
JDBC
连接参数关闭only_full_group_by
:jdbc:mysql://localhost:3306/test?sessionVariables=sql_mode='去除only_full_group_by后的值'
-