GROUP BY
語句是SQL中用來對數據實現分組聚集操作的語句,它可以根據數據表中的一個或多個屬性(列)的不同值把數據分成不同的組,以實現對數據的分組統計等操作。下面是我根據個人學習經驗對該語句做出的分析。
聚集函數
要了解分組的概念,首先讓我們來熟悉一下SQL中的基本聚集函數:
- 求平均值:
AVG()
- 找最小值:
MIN()
- 找最大值:
MAX()
- 求和:
SUM()
- 計數:
COUNT()
所有這些聚集函數,都是以一個集合作爲輸入,經過聚集作用後輸出一個值的函數,換言之,假設
假設一個企業工資管理數據庫中含有數據表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 分組聚集
如上所述,聚集函數是把整個數據表中的所有元組看成一個組來進行聚集映射,但是在實際中,我們常常會根據數據的某一個或多個屬性,把元組按其對應屬性值的不同分成多個不同的組。假設根據屬性
然後,對每一個分組都使用聚集函數並輸出相應分組的計算結果,因此,對一張數據表中的m個分組運用聚集函數後將會得到m個輸出
+----------+----------+
| 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
語句的學習總結,總結不到位或有錯誤之處歡迎大家指正。