MySQL錯誤-this is incompatible with sql_mode=only_full_group_by完美解決方案


項目場景:

有時候,遇到數據庫重復數據,需要將數據進行分組,並取出其中一條來展示,這時就需要用到group by語句。
但是,如果mysql是高版本,當執行group by時,select的字段不屬於group by的字段的話,sql語句就會報錯。報錯信息如下:

Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column ‘數據庫名.表名.字段名’ which is not functionally dependent
on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by



問題描述:

1.表結構

CREATE TABLE `t_iov_help_feedback` (
  `ID` INT(11) NOT NULL  AUTO_INCREMENT COMMENT '主鍵ID',
  `USER_ID` INT(255) DEFAULT NULL  COMMENT '用戶ID',
  `problems` VARCHAR(255) DEFAULT NULL COMMENT '問題描述',
  `last_updated_date` DATETIME DEFAULT NULL COMMENT '最后更新時間',
  PRIMARY KEY (`ID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;


2.表數據


3.sql語句


1)查詢group by的字段(正常

SELECT USER_ID  FROM  t_iov_help_feedback GROUP BY USER_ID;


SELECT MAX(ID),USER_ID  FROM  t_iov_help_feedback GROUP BY USER_ID;



2)查詢非group by的字段(報錯



報錯什么意思呢?


一句話概括:“錯誤代碼1055與sql_mode = only_full_group_by不兼容”
翻譯:

“錯誤代碼:1055。SELECT列表的表達式#1不在GROUP BY子句中,並且包含非聚合列’test.t_iov_help_feedback.ID’,它在功能上不依賴於GROUP BY子句中的列; 這與sql_mode = only_full_group_by不兼容”


原因分析:

一、原理層面
這個錯誤發生在mysql 5.7.5 版本及以上版本會出現的問題:
mysql 5.7.5版本以上默認的sql配置是:sql_mode=“ONLY_FULL_GROUP_BY”,這個配置嚴格執行了"SQL92標准"。
很多從5.6升級到5.7時,為了語法兼容,大部分都會選擇調整sql_mode,使其保持跟5.6一致,為了盡量兼容程序。



二、sql層面
在sql執行時,出現該原因,簡單來說就是:
由於開啟了ONLY_FULL_GROUP_BY的設置,如果select 的字段不在 group by 中,
並且select 的字段未使用聚合函數(SUM,AVG,MAX,MIN等)的話,那么這條sql查詢是被mysql認為非法的,會報錯誤…




驗證是否此原因:1.查詢數據庫版本的語句


SELECT VERSION();



可以看到,我這里數據庫版本是:8.0.16,大於5.7.5了

驗證是否此原因:2. 查看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_ENGINE_SUBSTITUTION


可以看到,sql_mode開啟了only_full_group_by 屬性


解決方案:

解決方案一:使用函數ANY_VALUE()包含報錯字段

將上述報錯語句改成:

SELECT ANY_VALUE(ID),USER_ID,ANY_VALUE(problems),ANY_VALUE(last_updated_date) FROM  t_iov_help_feedback GROUP BY USER_ID;



可以看到,結果能正常查詢了,根據需要自己改查詢字段的別名就行。

ANY_VALUE()函數說明:

MySQL有any_value(field)函數,它主要的作用就是抑制ONLY_FULL_GROUP_BY值被拒絕。
這樣sql語句不管是在ONLY_FULL_GROUP_BY模式關閉狀態還是在開啟模式都可以正常執行,不被mysql拒絕。
any_value()會選擇被分到同一組的數據里第一條數據的指定列值作為返回數據。
官方有介紹,地址:https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value 





解決方案二:通過sql語句暫時性修改sql_mode

去掉ONLY_FULL_GROUP_BY,重新設置值

SET @@global.sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';



上面是改變了全局sql_mode,對於新建的數據庫有效。對於已存在的數據庫,則需要在對應的數據庫下執行:

SET sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';


問題:

重啟mysql數據庫服務之后,ONLY_FULL_GROUP_BY還會出現,所以這只是暫時性的。


備注:
網上有些朋友提供的sql語句如下:

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


但是卻執行不了,報sql語法錯誤:


這時只需要加上單引號即可:



但是,添加了單引號仍然報錯:



解決方案三:通過配置文件永久修改sql_mode

mysql安裝在服務器上和安裝在本地,修改配置文件的方式有點區別。

1、Linux下修改配置文件


1)登錄進入MySQL
使用命令 mysql -u username -p 進行登陸,然后輸入密碼,輸入SQL:


show variables like ‘%sql_mode’;



2)編輯my.cnf文件
文件地址一般在:/etc/my.cnf,/etc/mysql/my.cnf
使用vim命令編輯文件,不知道vim命令怎么使用的,可以參考我的另外篇文章:Linux中使用vi工具進行文本編輯
找到sql-mode的位置,去掉ONLY_FULL_GROUP_BY
然后重啟MySQL;
有的my.cnf中可能沒有sql-mode,需要追加:

sql-mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION


注意要加入到[mysqld]下面,如加入到其他地方,重啟后也不生效,具體的如下圖:



3)修改成功后重啟MySQL服務

service mysql restart


重啟好后,再登錄mysql,輸入SQL:show variables like ‘%sql_mode’; 如果沒有ONLY_FULL_GROUP_BY,就說明已經成功了


如果還不行,那么只保留STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION 即可
追加內容為:

sql-mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION





2、window下修改配置文件


1)找到mysql安裝目錄,用記事本直接打開my.ini文件

在这里插入图片描述




2)編輯my.cnf文件,在[mysql]標簽下追加內容

sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

3)重啟mysql 服務


備注:
網上有些提供了sql_mode的值,卻導致重啟mysql服務啟動不了


sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION



這時,只需要將sql_mode 值中 “NO_AUTO_CREATE_USER” 這個屬性去掉即可。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM