錯誤信息
最近將測試環境做了遷移,發現在執行某一條未作任何改動的sql時,出現如下錯誤:
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #7 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'hmp-uat.trm.startTime' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #7 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'hmp-uat.trm.startTime' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
這個錯誤的意思:選擇的列沒有包含在GROUP BY子句中,而且包含了非聚合列,它在功能上不依賴於GROUP BY子句的列;這與sql mode=only_full_group_by完全不兼容。
簡單來說,就是查出來的字段必須是需要group by的這些字段中的一部分(隱約記得ORACLE是必須符合這個規則的)。
原因分析
上邊的是MyBatis拋出的異常信息,單獨執行SQL錯誤就是紅色的部分。未作遷移之前執行的好好的SQL,遷移后就不能正常執行了,做的事情就是換了MySQL版本,估計應該是MySQL版本導致的。原環境上mysql版本為5.6.x,新環境上的mysql我安裝的是5.7.21。
版本查詢
工具使用的navicat,查詢MySQL版本:
在鏈接上右鍵,打開命令行,或者直接快捷鍵F6,輸入如下命令:
select version();
結果如下:
mysql> select version(); +-------------------------+ | version() | +-------------------------+ | 5.7.21-0ubuntu0.16.04.1 | +-------------------------+ 1 row in set mysql>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
sql_mode查詢
同樣,在命令行輸入如下命令:
select @@GLOBAL.sql_mode;
結果如下:
mysql> select @@GLOBAL.sql_mode; +-------------------------------------------------------------------------------------------------------------------------------------------+ | @@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 | +-------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set mysql>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
可以看到,當前數據庫sql_mode確實包括了ONLY_FULL_GROUP_BY。開啟了這個模式,那么group by和select的字段就會嚴格匹配。
sql測試
接下來在5.7數據庫中做一個簡單的測試:
select id, name from t_hotel group by name
- 1.
如上,按照name分組,但是我需要查出來id和name兩個字段,結果是拋出異常:
[SQL]select id, name from t_hotel group by name
[Err] 1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'hmp-uat.t_hotel.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
正確的SQL寫法應該是這樣:
select id, name from t_hotel group by id, name
- 1.
需要查詢出來的列表id和name也必須作為分組的字段。
那么,這樣在寫SQL時限制較多,而且原來的應用需要改動,修改業務邏輯不太現實。最后的辦法是,將該選項關閉。
解決辦法
重新設置sql_mode,來關閉這個選項。
臨時修改
在navicate命令窗口,鍵入如下命令來修改:
set @@GLOBAL.sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
- 1.
其實就是去掉了ONLY_FULL_GROUP_BY,在查詢sql_mode可以看到設置成功。
但是這個方法如果重啟了mysql,設置就會失效,最后的辦法是永久關閉。
永久修改
打開/etc/mysql/my.cnf配置文件,在mysqld節點下添加如下配置:
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
- 1.
然后重啟mysql:
service mysql restart
再次執行sql,可以看到可以成功執行,問題解決。
表名大小區分
另外,mysql5.7默認也是開啟了表明的大小寫區分的,也可以通過修改配置文件來關閉,具體如下:
打開/etc/mysql/my.cnf配置文件,在mysqld節點下添加如下配置:
lower_case_table_names=1
1代表不區分大小寫,0代表區分,改完后,重啟mysql。
總結
mysql5.7默認開啟了很多功能,如果是數據庫升級,需要關閉一些選項,例如lower_case_table_names和ONLY_FULL_GROUP_BY,肯定還有其他問題,在測試過程中慢慢發現吧。
轉自:https://blog.belonk.com/c/Mysql_error_only_full_group_by.html