天天看點

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

本文首發:

MySQL only_full_group_by 1055報錯的三種解決方案,臨時關閉有影響嗎?

當我們遷移到 MySQL 5.7+ 的版本時,常會碰到

ERROR 1055 only_full_group_by

錯誤,這是 5.7 之後

SQL_MODE

預設打開了嚴格模式導緻的錯誤。說明你代碼裡有地方寫的不嚴謹。

ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause 
and contains nonaggregated column 'kalacloud.user_id' which is not functionally 
dependent on columns in GROUP BY clause; this is incompatible 
with sql_mode=only_full_group_by           

我看到大多數教程,隻寫了解決這個問題「術」的部分,并沒有講解什麼原因導緻這個錯誤。本教程先從原理講起,先讓大家了解為什麼會出錯。然後給出三種解決方案:「徹底解決」、「臨時解決」和「折中解決」,你可根據自己的實際情況進行選擇。

SQL_MODE 是什麼?

ONLY_FULL_GROUP_BY

錯誤前,我們先來說一下

SQL_MODE

。了解 MySQL 工作原理能更好的幫你了解錯誤發生的本質原因。

SQL_MODE

是 MySQL 中的一個環境變量,定義了 MySQL 支援的 SQL 文法和資料校驗程度。

SQL_MODE

一共三種模式

  • ANSI 模式:寬松模式。對插入資料進行校驗,如不符合定義類型或長度,對儲存資料進行截斷。
  • TRADITIONAL 模式:嚴格模式。對插入資料進行嚴格校驗,保證錯誤資料不能插入,ERROR 報錯。用于事物時,事物會進行復原。
  • STRICT_TRANS_TABLES 模式:嚴格模式。對插入資料進行嚴格校驗,錯誤資料不能插入,ERROR 報錯。

MySQL 5.7.4 之前,MySQL 預設不開啟嚴格模式

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

這是 MySQL 更新到5.7.5 之後預設SQL_MODE 為嚴格模式:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

擴充閱讀:

MySQL 連接配接數過多的處理方法合集 - Too many connections

SQL_MODE 嚴格模式的意義

在寬松模式下,即便 insert 一個錯誤的資料,MySQL 也會不加判斷的全盤接受。

我們來看一個執行個體

我們首先關閉

SQL_MODE

嚴格模式

set session sql_mode='';           

然後我們建立一個表并向其中插入一組超範圍的資料

create table kalacloud_t1(website char(9));
insert into kalacloud_t1 values('kalacloud.com');           

傳回值:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

從傳回值可以看出,我們向

websie

cher(9)

中插入了一條長為 13 的值,沒有報錯,直接插入,但超過 9 的部分,即「.com」被截斷丢掉了。

接着我們在嚴格模式下試試,首先打開

SQL_MODE

嚴格模式:

set session sql_mode='TRADITIONAL';           
create table kalacloud_t2(website char(9));
insert into kalacloud_t2 values('kalacloud.com');           
MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

我們可以從傳回值看出,MySQL 直接報錯,告訴你插入的資料有問題。

MySQL 配置檔案 my.cnf / my.ini 逐行詳解

ONLY_FULL_GROUP_BY 問題及解決方案

接着我們來說說

ONLY_FULL_GROUP_BY

的問題。當我們資料庫遷移至 5.7 或者 8.0 之後,最常見的錯誤就是

Error 1055 only_full_group_by

錯誤。

正如我前文所寫,這個錯誤的關鍵原因是不規範的 SQL 文法,5.7 之後預設

SQL_MODE

變為嚴格模式。

我們來一起看一個執行個體,這是一組

卡拉雲

使用者點選網頁的 log 記錄:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

現在我們使用

GROUP BY

來排序找出通路量最大的網頁。

我們先關掉

sql_mode

的嚴格模式來試試:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

在寬松模式下,我們可以看出這個 query 雖然可以查詢,但文法和邏輯上稍有問題。我們想對

page_url

進行排序,但 query 中也加入了

user_id

,在傳回值中可以發現問題,index.html 這個頁面不僅 user_id 1 的使用者通路過,使用者 2 和 3 也通路了,那麼這張傳回的表表格資料就是有問題的。

user_id 1 列在傳回資料裡,到底代表什麼?是第一個通路 index.html 還是最後一個通路這個頁面的意思呢?沒人知道,這是個随機盲盒,運作原理未知。

我們打開

sql_mode

嚴格模式跑一下上面這段代碼:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

傳回一個 ERROR 1055 報錯。

ONLY_FULL_GROUP_BY

SQL_MODE

TRADITIONAL

的選項參數,從 5.7 開始預設開啟為嚴格模式。這就是為什麼大家遷移到 MySQL 新版會報 1055 錯誤的原因。

我們已經了解了這個問題的原理原因,接下來,碰到

ONLY_FULL_GROUP_BY

報錯,我們應該怎麼處理呢?

如何在 MySQL 中查詢資料庫中帶有某個字段的所有表名

解決方案 1 – 重寫代碼

找到報錯文法中錯誤的部分,根據邏輯重寫 query,本示例中,我們去掉

user_id

即可。

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

如果你有大量在舊版 SQL 完成的代碼,檢查這種錯誤很有可能是相當浩大的工程。這時就到了你的決斷時刻了,你有兩條路可選:

(1)幹脆推翻重寫,讓代碼保持嚴謹和整潔,養成良好的習慣,避免未來出現的未知錯誤。

(2)了解原理。知道可能會出現的問題,關掉嚴格模式,回到寬松模式,接着用舊版代碼。

解決方案 2 – 傳回寬松模式

如果你碰到 ERROR 1055 報錯,但也不想在浩如煙海的代碼中糾錯,那麼你可以回到「寬松模式」接着用。

在 MySQL 5.7 及以上版本中 SQL_MODE 包含

ONLY_FULL_GROUP_BY、STRINCT_TRANS_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER           

我們直接在 MySQL 配置檔案中更改,或者臨時全部關閉:

SET GLOBAL sql_mode='';           

或者單關閉

ONLY_FULL_GROUP_BY

MariaDB [kalacloud_demo]> SET GLOBAL sql_mode='STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_ENGINE_SUBSTITUTION';           

解決方案 3 – 使用聚合函數

如果某些特别的原因就是要查詢

user_id

,但你又沒空改代碼,那麼我可使用聚合函數來規避這類錯誤,算是一種折中的方案了,文法改嚴謹了,代碼又不需要大動。

我們可以使用

MAX()

MIN()

或者

GROUP_CONCAT()

聚合函數。

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

MySQL 還提供了

ANY_VALUE()

函數,來解決這類問題:

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?
MySQL 分組查詢實戰 如何查詢每組第一、最後、單多字段查詢、分組篩選、最大小值排序

總結和推薦

在代碼嚴謹、清晰的道路上走多遠都不為過,我個人推薦使用第一種解決方案,趁着這一次機會,把你代碼中潛藏的隐患一網打盡。之後遵循嚴謹的代碼邏輯來寫代碼。當然,有很多特殊情況,你也可以參照方案二、三來臨時處理。

接着推薦一下我開發的

,隻要你會寫 MySQL ,就能使用卡拉雲搭建自己的資料工具,比如,資料看闆,企業 CRM、ERP,權限管理背景,對賬系統等。

卡拉雲是新一代低代碼開發工具,免安裝部署,可一鍵接入包括 MySQL 在内的常見資料庫及 API。可根據自己的工作流,定制開發。無需繁瑣的前端開發,隻需要簡單拖拽,即可快速搭建企業内部工具。數月的開發工作量,使用卡拉雲後可縮減至數天。

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

卡拉雲可一鍵接入常見的資料庫及 API

卡拉雲可根據公司工作流需求,輕松搭建資料看闆或其他内部工具,并且可一鍵分享給組内的小夥伴。

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

下圖為使用卡拉雲在 5 分鐘内搭建的「

優惠券發放核銷

」背景,僅需要簡單拖拽即可快速生成前端元件,隻要會寫 SQL,便可搭建一套趁手的資料庫工具。立即使用

MySQL only_full_group_by 1055 報錯的三種解決方案,臨時關閉有影響嗎?

有關 MySQL 教程,可繼續拓展學習: