SQL GROUP BY 語句分析

GROUP BY 語句是SQL中用來對數據實現分組聚集操作的語句,它可以根據數據表中的一個或多個屬性(列)的不同值把數據分成不同的組,以實現對數據的分組統計等操作。下面是我根據個人學習經驗對該語句做出的分析。

聚集函數

要了解分組的概念,首先讓我們來熟悉一下SQL中的基本聚集函數:

  • 求平均值: AVG()
  • 找最小值: MIN()
  • 找最大值: MAX()
  • 求和: SUM()
  • 計數: COUNT()

所有這些聚集函數,都是以一個集合作爲輸入,經過聚集作用後輸出一個值的函數,換言之,假設 x1,x2......xn 是一個數據表內的各個元組,則聚集函數就是關於所有這些元組的函數:

Output=f(x1,x2......xn)
因此,對整個數據表使用聚集函數,相當於將表中的所有元組看成一個組,然後用相應的聚集函數作用於這個組中的所有元素,得到一個輸出值。下面我們來看一個例子:
假設一個企業工資管理數據庫中含有數據表employees如下:

這裏寫圖片描述

我們使用聚集函數COUNT()來計算表中元組的總個數:

SELECT COUNT(*) FROM employees;

可以得到輸出結果爲:

+----------+
| COUNT(*) |
+----------+
| 4        |
+----------+

在這裏,COUNT() 把表中的4個元組看成一組,然後把該組中各個元組作爲自變量輸入,統計它們的總個數後輸出計數結果。

對於含有 WHERE 選擇子句的查詢語句,則先對錶中的每個元組進行篩選,選出符合條件的元組合成一個組,再將該組中的各個元組作爲自變量輸入到 COUNT() 函數中計算結果。
統計employees表中女員工的數量:

SELECT COUNT(*)
FROM employees E
WHERE E.gender = 'F';

輸出結果爲:

+----------+
| COUNT(*) |
+----------+
| 2        |
+----------+

GROUP BY 分組聚集

如上所述,聚集函數是把整個數據表中的所有元組看成一個組來進行聚集映射,但是在實際中,我們常常會根據數據的某一個或多個屬性,把元組按其對應屬性值的不同分成多個不同的組。假設根據屬性 Y 來對數據進行分組,Y 的值有 y1,y2,......ym ,共m個不同的值,則對一張表的數據分組後有:
這裏寫圖片描述
然後,對每一個分組都使用聚集函數並輸出相應分組的計算結果,因此,對一張數據表中的m個分組運用聚集函數後將會得到m個輸出 r1,r2......rm 輸出的形式如下所示:

+----------+----------+
| Y        | result   |
+----------+----------+
| y1       | r1       |
+----------+----------+
| y2       | r2       |
+----------+----------+
| ...      | ...      |
+----------+----------+
| ym       | rm       |
+----------+----------+

我們再以上面的employees表爲例子,這次我們爲每個元組增加一個工資salary的屬性:

這裏寫圖片描述

然後我們用分組聚集函數,分別計算男員工和女員工的平均工資:

SELECT AVG(salary)
FROM employees
GROUP BY gender;

輸出結果爲:

+--------------+
| AVG(salary)  |
+--------------+
| 15000.000000 |
+--------------+
| 13825.000000 |
+--------------+

統計結果雖然出來了,但我們並不知道上面的結果分別是對應哪個分組的,因此把分組的屬性顯示出來:

SELECT gender, AVG(salary)
FROM employees
GROUP BY gender;

輸出結果爲:

+--------+--------------+
| gender | AVG(salary)  |
+--------+--------------+
| M      | 15000.000000 |
+--------+--------------+
| F      | 13825.000000 |
+--------+--------------+

在這裏需要特別注意一點,這個在《數據庫系統概念 第六版》中也有強調:

當SQL查詢使用分組時,一個很重要的事情是需要保證出現在 select 語句中但沒有被聚集的屬性只能是出現在 group by 子句中的那些屬性。換句話說,任何沒有出現在 group by 子句中的屬性如果出現在 select 子句中的話,它只能出現在聚集函數內部,否則這樣的查詢就是錯誤的。

例如,如下的查詢是錯誤的:

SELECT name, gender, AVG(salary)
FROM employees
GROUP BY gender;

這是因爲,name既沒有出現在 GROUP BY 中,也沒有出現在聚集函數 AVG() 的內部。
然而在本人所使用的mysql 5.5.53數據庫管理系統中,這種錯誤是允許的,mysql將會把每個分組的第一個元組的name顯示出來,上述錯誤語句在mysql5.5.53中的執行結果爲:

+---------------+---------+--------------+
| name          | gender  | AVG(salary)  |
+---------------+---------+--------------+
| Jackie Cheng  | M       | 15000.000000 |
+---------------+---------+--------------+
| Anna May Wong | F       | 13825.000000 |
+---------------+---------+--------------+

HAVING 子句

HAVING 子句用於對分組後根據每個組的運算結果對組進行篩選,選出符合條件的分組進行顯示。例如,對上面的employees表選出平均工資大於14000的分組:

SELECT gender, AVG(salary)
FROM employees
GROUP BY gender
HAVING AVG(salary) > 14000;

輸出結果如下:

+--------+--------------+
| gender | AVG(salary)  |
+--------+--------------+
| M      | 15000.000000 |
+--------+--------------+

注意 HAVING 子句也與 SELECT 子句的限制條件一樣,其後面的屬性只能是出現在 GROUP BY 子句中的那些屬性!如果不滿足這個條件,mysql數據庫管理系統也會報錯:

SELECT gender, AVG(salary)
FROM employees
GROUP BY gender
HAVING name = 'Jackie Cheng';

報錯如下:

Error Code: 1054. Unknown column 'name' in 'having clause'  0.016 sec



以上是我個人對SQL中的聚集函數、GROUP BY 語句和 HAVING 語句的學習總結,總結不到位或有錯誤之處歡迎大家指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章