淺析MySQL使用 GROUP BY 分組聚合與細分聚合

来源:http://www.cnblogs.com/weix-l/archive/2017/09/14/7521278.html
-Advertisement-
Play Games

原創文章,轉載請註明出處:http://www.cnblogs.com/weix-l/p/7521278.html; 若有錯誤,請評論指出,謝謝! 1. 聚合函數(Aggregate Function) MySQL(5.7 ) 官方文檔中給出的聚合函數列表(圖片)如下: 詳情點擊https://de ...


  原創文章,轉載請註明出處:http://www.cnblogs.com/weix-l/p/7521278.html

  若有錯誤,請評論指出,謝謝!

1. 聚合函數(Aggregate Function)

  MySQL(5.7 ) 官方文檔中給出的聚合函數列表(圖片)如下:

詳情點擊https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html 。

  除非另有說明,否則聚合函數都會忽略空值(NULL values)。

2. 聚合函數的使用

  聚合函數通常對 GROUP BY 語句進行分組後的每個分組起作用,即,如果在查詢語句中不使用 GROUP BY 對結果集分組,則聚合函數就對結果集的所有行起作用。為說明聚合函數的使用,現創建測試表 member 進行測試,member 的數據結構如下(使用 SELECT * FROM member 查詢所得):

  

 

  1)對結果集直接使用聚合函數

  例如,使用聚合函數SUM () 計算所有會員(member) 的會費總和,則可使用:

SELECT SUM(fee) AS total_fee FROM member    #計算所有會員會費總和

查詢結果為:

  

SUM 函數會對全部欄位列 fee 進行求和。當然,也可以求平均值、最大值等。

  此外,也可以使用 WHERE 語句進行限定條件的聚合查詢。例如,如果要查詢 country 為 China 的會員會費之和,則為:

SELECT SUM(fee) AS China_total_fee, country FROM member WHERE country = 'China'

結果顯示如下:

  

 

  2)GROUP BY 對結果集分組後使用聚合函數——組內聚合

  • GROUP BY 如何分組?

   ——將欄位值相同的記錄歸為一組,可用COUNT(*) 統計組內成員個數

  • “組內聚合”為何意?

   ——以分組為單位,對組內每個成員使用聚合函數進行統計,即聚合函數是關於分組成員的函數

  試想,如果要從測試表中查詢每個國家的會費總和呢?每個國家的會費,即先將所有結果集按 country 欄位進行分組,country 值相同的行歸為一組,然後以組為單位進行求和,這樣查詢的結果記錄數等於分組欄位不同值的個數。總共有來自三個國家(China, US, UK)的會員,所以分組聚合查詢的結果記錄數為3:

SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country  #查詢每個國家的會費之和

該查詢語句會計算每個國家的會費之和,然後展示按每個國家分組的查詢結果:

  

   標準SQL( standard SQL) 和 MySQL 都提供 HAVING 語句對使用 GROUP BY 分組之後的結果進行條件篩選並產生新的結果集。例如,對於前述 1)中查詢中國會員會費總和的問題,可以使用HAVING 語句:

SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country = 'China'     #使用HAVING語句查詢中國會員會費總和

結果和上面一樣:

  

  這種方法與前述 1)中直接使用WHERE進行限定相比有些畫蛇添足,為什麼呢?因為 country 在此是分組欄位(group column),對分組欄位使用 HAVING 再次進行限定則就顯得分組毫無意義,因為這時完全可以通過使用 WHERE 進行篩選後直接求和實現。那麼,能使用非聚合列(nonaggregated column) 為限定條件嗎?答案是,不僅沒有意義,而且不允許。非聚合列指的是沒有用聚合函數而是要查詢的表本身的欄位,因為使用 GROUP BY 分組查詢後的聚合結果列中根本就不包含非聚合欄位列,所以在解析SQL語句時根本找不到這個欄位。比如,當你想獲取每個國家性別為 man 的會員的會費之和時可能嘗試在上面這個語句中使用 HAVING 對 sex 進行限定,像下麵這樣:

SELECT SUM(fee) AS country_group_total_fee FROM member m GROUP BY country HAVING m.sex = 'man'    #錯誤:嘗試使用HAVING 語句對非聚合欄位進行限定

執行後會報錯 Err 1054:

[Err] 1054 - Unknown column 'm.sex' in 'having clause',提示未知的列m.sex,即使此處使用別名進行說明也不行。那麼如何實現查詢每個國家性別為 man 的會員的會費之和呢?當然還是使用WHERE 語句在 GROUP BY 進行分組之前就進行限定:

SELECT SUM(fee) AS country_group_total_fee, country FROM member WHERE sex = 'man' GROUP BY country    #在分組之前使用 WHERE 進行條件篩選

產生下麵結果:

   

  所以,HAVING 不能對分組本身起作用,但可以對分組後的結果進行查詢限定,而限定的條件只能為聚合列(aggregated column),聚合列指的是在 SELECT 列 (SELECT list)中使用聚合函數產生的列,例如,此處的SUM(fee) 就是聚合列。在HAVING 中對聚合列進行限定,可以獲取滿足一定條件的聚合列結果。例如,在上面獲取每個國家會員費用之和後再限定查詢哪些會員費用之和超過10000,則可以使用下麵的SQL 語句:

SELECT SUM(fee) country FROM member GROUP BY country HAVING SUM(fee) > 10000    #查詢會員費總和超過10000 的國家

其結果就只剩下中國了:)

  

 這是在標準SQL語句中的語法。在MySQL中擴展了HAVING 的用法,使其可以接受聚合列的別名作為限定條件,例如上面的要求使用別名的查詢語句為:

SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country_group_total_fee > 10000    #在HAVING 中使用別名

其結果仍為:

  

3)GROUP BY 按多個分組欄位分組後使用聚合函數——細分組內聚合

   如果使用一個分組欄位分組後的聚合結果記錄數等於該分組欄位不同值的個數,那麼,使用多個分組欄位以後呢?例如,在上面的查詢的基礎上,如果想要查詢每個國家男、女分別的會費總和時,可以使用下麵的語句:

SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex FROM member GROUP BY country,sex    #查詢每個國家男、女會員的總和會費

結果如下:

  

從上面的結果可以看出來,“中國的男性會員出的總會費最多,而英國的男性會員的總會費最少”。總共三個國家,如果只按國家(country) 進行分組,只有三條記錄,如果再按性別 (sex) 分,則會在分組後的每個組(也即每一行、每一條記錄)里按性別的不同再進行細分,因為性別值只有兩種,所以每個國家的分組又被分成兩小組,則三個國家總共就有6小組(6 = 3 × 2),這樣最終也就會有6條記錄,如上圖示。

  為瞭解每個細分小組的個數,在SELECT 查詢列的最後加上計算分組個數的聚合函數 COUNT(*):

SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, COUNT(*) AS row_num FROM member GROUP BY country, sex    #多分組欄位分組,並統計每組個數

結果如下:

  上面的結果預設按靠近GROUP BY 的順序進行排序,但如果要指定排序一句,則可使用ORDER BY ,例如,對上面的結果按 sex 排序:

SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, count(*) AS row_num FROM member GROUP BY country, sex ORDER BY sex    #將分組結果按sex 排序

結果如下:

  如果用其他欄位對結果再進行細分呢?原理與上述兩個欄位進行分組時一樣的,知識分組的深度越多,很明顯結果的記錄行數也越多,但不管怎樣,你會發現每一條分組後的結果都是不一樣的,這正是分組結果的特征,因為ORDER BY 本身就具有聚合功能,每個聚合列的結果是通過分組歸類的結果,所以只有一條記錄。

  那麼,如果用表的 主鍵 或 非空唯一性欄位 進行分組,結果會怎樣呢?比如,在本測試表中,id 是其主鍵,name 是非空的具有唯一性約束的欄位,下麵分別是以 id 和 name 進行分組的MySQL 語句和結果:

SELECT SUM(fee) AS sex_and_country_group_total_fee, id, COUNT(*) AS row_num FROM member GROUP BY id    #以主鍵id進行分組

結果如下:

  

SELECT SUM(fee) AS sex_and_country_group_total_fee, name, COUNT(*) AS row_num FROM member GROUP BY name    #以非空唯一性約束欄位進行分組

結果如下:

  

很顯然,這兩種分組的結果中聚合函數結果列是一樣的,每組的結果記錄行數也一樣,而且都為1,這說明按主鍵或非空唯一性約束欄位進行分組其結果相同,且結果就是表的全部每一行記錄。這樣做可能沒有太大意義,但有助於理解 GROUP BY 分組的原理。

3. 總結

  1) 可直接對某個欄位使用聚合函數,也可用 WHERE 語句篩選後對某個欄位使用聚合函數;

  2) 聚合函數通常作用於使用 GROUP BY 分組後的分組成員,用於統計每個分組的數據;

  3) 不能對沒有使用 GROUP BY 分組的聚合函數使用 HAVING  進行限定;

  4) 可對使用 GROUP BY 分組查詢後的結果使用 HAVING 進行限定,其限定條件最好為聚合函數列(本身或其他聚合函數);

  5) 可在使用 GROUP BY 分組前使用 WHERE 對結果進行篩選,在分組後使用 HAVING 對聚合函數列進行限定;

  6) 可使用 ORDER BY 對結果按照某個欄位(任意欄位或列,使用 GROUP BY 分組時也可使用聚合函數列)進行排序;

  7) 當按照主鍵或非空唯一性約束欄位進行分組時,其結果為整個表的全部記錄。

4. 參考文獻

  [1]. MySQL 官方文檔  URL: https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 文件和文件組填充策略 文件組對組內的所有文件都使用按比例填充策略。當數據寫入文件組時,SQL Server 資料庫引擎按文件中的可用空間比例將數據寫入文件組中的每個文件,而不是將所有數據都寫入第一個文件直至其變滿為止。然後再寫入下一個文件。例如,如果文件 f1 有 100 MB 可用空間,文件 f2 ...
  • --通過代碼方式新建資料庫create database MyDatabase0911New --(MyDatabase0911New要創建的資料庫名稱)on primary --資料庫文件( --名字 name='MyDatabase0911New_data', --路徑 filename='G: ...
  • SQL是Structure Query language(結構化查詢語言)的縮寫,它是使用關係模型的資料庫應用語言。在眾多開源資料庫中,MySQL正是其中最傑出的代表,MySQL是由三個瑞典人於20世紀90年代開發的一個關係型資料庫。並用了創始人之一Michael Widenius女兒的名字My命名 ...
  • 最近做了幾個PowerBI報表,對PowerBI的設計有了更深的理解,對數據的塑形(sharp data),不僅可以在Data Source中實現,例如在TSQL查詢腳本中,而且可以在PowerBI中實現,例如,向數據模型中添加自定義欄位,或者在報表數據顯示時,根據數據表之間的關係做數據的統計。本文 ...
  • 索引對於提高查詢性能非常有效,因此,一般應該考慮應該考慮為分區表建立索引,為分區表建立索引與為普通表建立索引的語法一直,但是,其行為與普通索引有所差異。預設情況下,分區表中創建的索引使用與分區表相同分區架構和分區列,這樣,索引將於表對齊。將表與其索引對齊,可以使管理工作更容易進行,對於滑動視窗方案尤 ...
  • 鍵值對RDD通常用來進行聚合計算,Spark為包含鍵值對類型的RDD提供了一些專有的操作。這些RDD被稱為pair RDD。pair RDD提供了並行操作各個鍵或跨節點重新進行數據分組的操作介面。 Spark中創建pair RDD的方法:存儲鍵值對的數據格式會在讀取時直接返回由其鍵值對數據組成的pa ...
  • 環境: A、B兩台伺服器分別安裝mysql-5.7.18服務端,配置成互為主從同步。 linux系統版本為CentOS7 A伺服器ip:192.168.1.7 主機名:test1 B伺服器ip:192.168.1.8 主機名:test2 (同一區域網下) 一、準備 1.修改主機名 命令:hostna ...
  • Oracle資料庫學習: 01.資料庫簡介: (1)文件型資料庫: Access Office組件: Foxpro (2)NoSql資料庫(泛指非關係型資料庫): NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”,是一項全新的資料庫革命性運動,早期就有人提出,發展至2 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...