only_full_group_by問題而引起的對group by的深刻思考

問題背景

最近在項目中使用mysql的group by進行分組查詢的場景比較多,其中一次遇到了一個問題,即在開發環境執行一個以下sql時是正確且可執行的,mysql

select a,b,max(c) from test_tbl group by a

可是放到了測試環境就會報以下的錯誤。sql

[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'your_tbl...' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

解決辦法

由於開發環境和測試環境所使用的mysql數據庫的版本不同,開發環境使用的時候5.6.x而測試環境使用的是5.7.x,而在Mysql的5.7.x版本中默認是開啓sql_mode = only_full_group_by
而在這個模式下,咱們使用分組查詢時,出如今select字段後面的只能是group by後面的分組字段,或使用聚合函數包裹着的字段。
在上面的sql中,字段b既不是group by裏面的分組字段,也沒有被聚合函數包裹着。5.7如下的版本不進行檢查,而5.7以上的版本進行了sql_mode=only_full_group_by的檢查,因此會出現以上的問題,固然解決方法也很簡單,將b也歸入到分組字段中便可。數據庫

group by深刻思考

雖然在工做中會頻繁的使用到group by進行分組查詢,但本身對數據分組這個概念一直很模糊,此次就藉着這個機會,經過一個簡單的示例來幫助你們在腦海中創建起來數據分組這個抽象概念。
函數

咱們建立一張以下的數據表測試

CREATE TABLE `product` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `product_name` varchar(100) NOT NULL COMMENT '商品名稱',
  `brand_name` varchar(100) DEFAULT NULL COMMENT '品牌名稱',
  `category_name` varchar(100) NOT NULL COMMENT '商品分類',
  `price` decimal(10,4) NOT NULL COMMENT '價格'
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='測試用的商品表';

表中有以下數據this

mysql> select * from product;
+----+---------------+------------+---------------+-------+
| id | product_name  | brand_name | category_name | price |
+----+---------------+------------+---------------+-------+
|  1 | XiaoMi6X      | XiaoMi     | 手機          | 2999  |
|  2 | XiaoAi        | Lenovo     | 電腦          | 8999  |
|  3 | HUAWEI K1     | HUAWEI     | 手機          | 1999  |
|  4 | iPhone X      | iPhone     | 手機          | 9999  |
|  5 | MacBook Pro   | Mac        | 電腦          | 13999 |
|  6 | iPhone XMAX   | iPhone     | 手機          | 10999 |
|  7 | HUAWEI Mate20 | HUAWEI     | 手機          | 2999  |
+----+---------------+------------+---------------+-------+
7 rows in set

一個最高價

咱們使用group by按照品牌類目(category_name)進行分組,並獲取該分組中的最高價格。spa

mysql> select category_name,max(price) from product group by category_name;
+---------------+------------+
| category_name | max(price) |
+---------------+------------+
| 手機          | 10999      |
| 電腦          | 13999      |
+---------------+------------+
2 rows in set

這個簡單的分組sql相信也難不倒你們,那麼讓咱們來看看這個分組查詢語句是如何取到最終結果的。code

過程:以下圖所示,首先從數據集中篩選出來類目爲手機的全部記錄(以藍色線框標明)和類目爲電腦的全部記錄(以紅色線框標明)並將這些記錄歸集到一塊兒,那麼分組以後就出現了以不一樣類目進行劃分的兩個數據集,而後再從各自的數據集中選出最高的價格即可獲得最終的結果。blog

一個最低價

再舉一個例子,咱們用品牌名稱brand_name進行分組,並使用聚合函數算出該品牌下的最低價格。ci

mysql> select brand_name,min(price) from product group by brand_name;
+------------+------------+
| brand_name | min(price) |
+------------+------------+
| HUAWEI     | 1999       |
| iPhone     | 9999       |
| Lenovo     | 8999       |
| Mac        | 13999      |
| XiaoMi     | 2999       |
+------------+------------+
5 rows in set

過程:以下圖所示,從數據集中按照品牌名稱brand_name進行分組,而後按照品牌名稱就篩選出了一共五組品牌,而後再從各自品牌中選出最低價格即可獲得最終結果。

後記總結

取經歸來後,愈發的以爲不管生活仍是技術都應該持有一種脫離表層、嚮往深層的探索追求精神,在這個過程當中我會不斷的總結分享,與諸君共勉! 

相關文章
相關標籤/搜索