《SQL必知必會》筆記5-聚集函數(avg、count、max、min、sum)、分組(group by、having)

1 使用聚集函數匯總數據(AVG、COUNT、MAX、MIN、SUM)

我們經常需要匯總數據而不用把它們都檢索出來。比如:

  • 確定表中行數(或者滿足某個條件或包含某個特定值的行數)。
  • 獲得表中某些行的和。
  • 找出表列(或所有行或者某些特定行)的最大值、最小值、平均值。

聚集函數(aggregate function):對某些行運行的函數,計算并返回一個值。

SQL給了5個聚集函數。

函數 說明
AVG() 返回某列的平均值
COUNT() 返回某列的行數
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值的總和

1.1 AVG()函數

AVG()函數通過對表中行數計數并計算其列值之和,求得該列的平均值。AVG()可用來返回所有列的平均值,也可以返回特定列或行的平均值。

計算Products表中所有產品的平均價格:

SELECT AVG(prod_price) AS avg_price 
FROM Products;

計算特定供應商DLL01所提供產品的平均價格:

SELECT AVG(prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';

注意:AVG()只能用來確定特定數值列的平均值,而且列名必須作為函數參數給出。為了獲得多個列的平均值,必須使用多個AVG()函數,如AVG(num1)、AVG(num2)、AVG(num3)等。

AVG()函數在計算時,會忽略列值為NULL的行。


1.2 COUNT()函數

COUNT()函數進行計數,可確定表中行的數目或符合特定條件的行的數目。

COUNT()函數有兩種使用方式:

  1. 使用COUNT(*)對表中行的數目進行計數,不管表列中包含的是空值NULL還是非空值。
  2. 使用COUNT(column)對特定列中具有值的行進行計數,忽略NULL值。

計算Customers表中顧客的總數:

SELECT COUNT(*) AS num_cust 
FROM Customers;

只計算有Email的顧客:

SELECT COUNT(cust_email) AS num_cust 
FROM Customers;

1.3 MAX()函數

MAX()函數返回指定列中的最大值,要求必須指定列名。

計算Products表中最貴物品的價格:

SELECT MAX(prod_price) AS max_price 
FROM Products;

雖然MAX()一般用來找出最大的數值或日期值,但許多DBMS允許將它用來返回任意列中的最大值,包括返回文本列中的最大值。用于文本數據時,MAX()返回按該列排序后的最后一行。

MAX()函數會忽略列值為NULL的行。


1.4 MIN()函數

MIN()函數返回指定列中的最小值,要求必須指定列名。

計算Products表中最便宜物品的價格:

SELECT MIN(prod_price) AS min_price 
FROM Products;

雖然MIN()一般用來找出最小的數值或日期值,但許多DBMS允許將它用來返回任意列中的最小值,包括返回文本列中的最小值。用于文本數據時,MIN()返回按該列排序后最前面的行。

MIN()函數會忽略列值為NULL的行。


1.5 SUM()函數

SUM()函數用來返回指定列值的和(總計)。

計算訂單號為20005的所購物品的總數:

SELECT SUM(quantity) AS items_ordered
FROM OrderItems 
WHERE order_num = 20005;

計算訂單號為20005的所購物品,花費的總金額:

SELECT SUM(item_price * quantity) AS total_price
FROM OrderItems 
WHERE order_num = 20005;

SUM()函數會忽略列值為NULL的行。


1.6 聚集不同的值

  • 對所有行執行計算,指定ALL參數或者不指定參數(ALL是默認行為)。
  • 只包含不同的值,指定DISTINCT參數。

計算特定供應商DLL01提供的產品的不同價格的平均值,也就是排除相同價格的產品。

SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products 
WHERE vend_id = 'DLL01';

在使用了DISTINCT之后,發現avg_price比較高,是因為有多個產品具有相同的較低價格,排除它們,提高了平均價格。

注意:如果指定列名,則DISTINCT只能用于COUNT()。DISTINCT不能用于COUNT(*)。DISTINCT必須使用列名,不能用于計算或表達式。

有些DBMS支持對查詢結果子集進行計算的TOP和TOP PERCENT。


1.7 組合聚集函數

計算Products表中物品的數目,產品價格的最大值、最小值以及平均值。

SELECT COUNT(*) AS num_items,
       MIN(prod_price) AS price_min,
       MAX(prod_price) AS price_max,
       AVG(prod_price) AS price_avg
FROM Products;

2 分組數據(GROUP BY、HAVING)

2.1 創建分組(GROUP BY)

SELECT vend_id, COUNT(*) AS num_prods
FROM Products 
GROUP BY vend_id;

在使用GROUP BY子句前,需要知道一些重要的規定。

  1. GROUP BY子句可以包含任意數目的列,因而可以對分組進行嵌套,更細致地進行數據分組。
  2. 如果在GROUP BY子句中嵌套了分組,數據將在最后指定的分組上進行匯總。換句話說,在建立分組時,指定的所有列都一起計算,不能從個別的列取回數據。
  3. GROUP BY子句中列出的每一列都必須是檢索列或有效的表達式(但不能是聚集函數)。如果在SELECT中使用表達式,則必須在GROUP BY子句中指定相同的表達式,不能使用別名。
  4. 大多數SQL實現不允許GROUP BY列帶有長度可變的數據類型(如文本或備注型字段)。
  5. 除聚集計算語句外,SELECT語句中的每一列都必須在GROUP BY子句中給出。
  6. 如果分組列中包含具有NULL值的行,則NULL將作為一個分組返回。如果列中有多行NULL值,它們將分為一組。
  7. GROUP BY子句必須出現在WHERE子句之后,ORDER BY子句之前。

有的SQL實現允許根據SELECT列表中的位置指定GROUP BY的列,例如,GROUP BY 2,1可表示按選擇的第二個列分組,然后再按第一個列分組。


2.2 過濾分組(HAVING)

除了能用GROUP BY分組數據外,SQL還允許過濾分組。規定包括哪些分組,排除哪些分組。例如,你可能想要列出至少有兩個訂單的所有顧客。為此,必須基于完整的分組而不是個別的行進行過濾。

在這個例子中WHERE不能完成任務,因為WHERE過濾指定的是行而不是分組。事實上,WHERE沒有分組的概念。

那么,不使用WHERE使用什么呢?SQL為此提供了另一個子句,就是HAVING子句。HAVING非常類似于WHERE,唯一的區別是,WHERE過濾行,而HAVING過濾分組。

SELECT cust_id, COUNT(*) AS orders
FROM Orders 
GROUP BY cust_id
HAVING COUNT(*) >= 2;

HAVING過濾了COUNT(*)>=2(兩個以上訂單)的那些分組。

WHERE子句在這里不起作用,因為過濾是基于分組聚集值,而不是特定行的值。

WHERE在數據分組前進行過濾,HAVING在數據分組后進行過濾。

SELECT vend_id, COUNT(*) AS num_prods
FROM Products 
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;

這條語句中,第一行是使用了聚集函數的基本SELECT語句,很像前面的例子。WHERE子句過濾所有prod_price至少為4的行,然后按vend_id分組數據,HAVING子句過濾計數為2或2以上的分組。如果沒有WHERE子句,就會多檢索一行(供應商DLL01,銷售4個產品,價格都在4以下)。

SELECT vend_id, COUNT(*) AS num_prods
FROM Products 
GROUP BY vend_id
HAVING COUNT(*) >= 2;

注意:使用HAVING時應該結合GROUP BY子句,而WHERE子句用于標準的行級過濾。


2.3 分組和排序(GROUP BY、ORDER BY)

GROUP BY和ORDER BY經常完成相同的工作,但它們非常不同。

ORDER BY GROUP BY
對產生的輸出排序 對行分組,但輸出可能不是分組的順序
任意列都可以使用(甚至非選擇的列也可以使用) 只可能使用選擇列或表達式列,而且必須使用每個選擇列表達式
不一定需要 如果與聚集函數一起使用列(或表達式),則必須使用

一般在使用GROUP BY子句時,應該也給出ORDER BY子句。這是保證數據正確排序的唯一方法,千萬不要僅依賴GROUP BY排序數據。

檢索包含三個或更多物品的訂單號和訂購物品的數目。

SELECT order_num, COUNT(*) AS items
FROM OrderItems 
GROUP BY order_num
HAVING COUNT(*) >= 3;

要按訂購物品的數目排序輸出,需要添加ORDER BY子句。

SELECT order_num, COUNT(*) AS items
FROM OrderItems 
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num;

2.4 SELECT子句順序

SELECT子句及其順序

子句 說明 是否必須
SELECT 要返回的列或表達式
FROM 從中檢索數據的表 僅在從表選擇數據時使用
WHERE 行級過濾
GROUP BY 分組說明 僅在按組計算聚集時使用
HAVING 組級過濾
ORDER BY 輸出排序順序

如果您發現文中有不清楚或者有問題的地方,請在下方評論區留言,我會根據您的評論,更新文中相關內容,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容