問題
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后的值'
-