連載的上一篇文章队魏,我們講到通過 SQL 聚合函數(shù)可以匯總數(shù)據(jù)公般,比如對行進(jìn)行計數(shù),計算和與平均數(shù)胡桨,獲取最大值和最小值官帘。
但目前為止,我們的匯總都是正對所有行或匹配 WHERE 子句的數(shù)據(jù)上進(jìn)行的昧谊。比如返回供應(yīng)商 DLL01
提供的產(chǎn)品數(shù)目:
SELECT
COUNT( * ) AS num_prods
FROM
Products
WHERE
vend_id = 'DLL01';
運(yùn)行結(jié)果:
那如果我們想要返回每個供應(yīng)商提供的產(chǎn)品數(shù)目呢刽虹?這就需要用到分組聚合了。使用分組可以將數(shù)據(jù)分為多個邏輯組呢诬,然后對每個組進(jìn)行聚合計算涌哲。
分組
分組的創(chuàng)建使用 SELECT
語句中的 GROUP BY
子句,比如下面的 SQL 返回每個供應(yīng)商提供的產(chǎn)品數(shù)目:
SELECT
vend_id,
COUNT( * ) AS num_prods
FROM
Products
GROUP BY
vend_id;
運(yùn)行結(jié)果:
上述 SELECT 語句返回兩個列尚镰,vend_id
為供應(yīng)商 ID阀圾,是分組字段;num_prods
為計算字段狗唉,使用 count(*)
聚合而來初烘。GROUP BY
子句告訴 DBMS 按 vend_id
排序并分組數(shù)據(jù),然后對每個分組而不是整個數(shù)據(jù)集進(jìn)行聚合分俯。
注 1:GROUP BY 子句可以包含多個列肾筐,即允許分組嵌套。此外缸剪,除聚合函數(shù)返回的計算字段外吗铐,SELECT 語句后跟的每一列都必須在 GROUP BY 子句中給出。
注 2:如果分組中存在 NULL 值的行杏节,則 NULL 將作為一個分組返回唬渗;多個 NULL 值將被分為一組讥此。
過濾分組
除了使用 GROUP BY 分組數(shù)據(jù)外,SQL 還允許過濾分組谣妻,規(guī)定包含哪些分組,排除哪些分組卒稳。比如蹋半,我們只想列出供應(yīng)產(chǎn)品數(shù)目在 2 種以上的供應(yīng)商及其供應(yīng)產(chǎn)品的數(shù)目。
這里有個過濾條件:供應(yīng)產(chǎn)品數(shù)目大于 2充坑,條件中的 供應(yīng)產(chǎn)品數(shù)目 是針對分組后進(jìn)行聚合產(chǎn)生的計算字段减江,因此無法使用 WHERE 子句。WHERE 子句過濾時指定的是行捻爷,而不是分組辈灼。
為此,SQL 提供了 HAVING
子句來過濾分組也榄,并且 HAVING
支持所有 WHERE
操作符巡莹。下面,我們來完成供應(yīng)產(chǎn)品數(shù)目在 2 種以上的供應(yīng)商及其供應(yīng)產(chǎn)品的數(shù)目甜紫。
SELECT
vend_id,
COUNT( * ) AS num_prods
FROM
Products
GROUP BY
vend_id
HAVING
num_prods > 2;
運(yùn)行結(jié)果:
跟前面的結(jié)果相比降宅,供應(yīng)產(chǎn)品數(shù)目等于 2 的供應(yīng)商信息就不見啦~
注:WHERE 過濾行,HAVING 過濾分組囚霸。也可以理解為 WHERE 在分組前進(jìn)行過濾腰根,HAVING 在數(shù)據(jù)分組后進(jìn)行過濾。
關(guān)于 WHERE
子句和 HAVING
子句的區(qū)別拓型,我們可以再通過一個案例理解一下额嘿。下面的 SQL 檢索具有兩個或以上產(chǎn)品且其價格大于等于 4 的供應(yīng)商。
其中產(chǎn)品表如下:
SQL 語句如下:
SELECT
prod_id,
COUNT( * ) AS prod_num
FROM
Products
WHERE
prod_price >= 4
GROUP BY
vend_id
HAVING
prod_num >= 2;
運(yùn)行結(jié)果:
附:SELECT 子句順序
截止目前劣挫,我們已經(jīng)學(xué)了不少的 SELECT 子句册养,下面小魚針對目前我們已經(jīng)學(xué)習(xí)的 SELECT 子句來總結(jié)一下他們在 SELECT 語句中的先后順序。
表中子句的排列順序即為它們在 SELECT 語句中依次出現(xiàn)的次序:
子句 | 說明 | 是否必須使用 |
---|---|---|
SELECT | 返回的列或表達(dá)式 | 是 |
FROM | 從中檢索數(shù)據(jù)的表 | 僅在從表中檢索數(shù)據(jù)時使用 |
WHERE | 行級過濾 | 否 |
GROUP BY | 分組數(shù)據(jù) | 僅在分組聚合時使用 |
HAVING | 組級過濾 | 否 |
ORDER BY | 對結(jié)果進(jìn)行排序 | 否 |
還是上面的例子压固,檢索具有兩個或以上產(chǎn)品且其價格大于等于 4 的供應(yīng)商和其供應(yīng)的產(chǎn)品數(shù)目捕儒,不過檢索檢索需要按照產(chǎn)品數(shù)目升序排列。
SELECT
prod_id,
COUNT( * ) AS prod_num
FROM
Products
WHERE
prod_price >= 4
GROUP BY
vend_id
HAVING
prod_num >= 2
ORDER BY
prod_num;
運(yùn)行結(jié)果:
總結(jié)
本節(jié)邓夕,我們學(xué)習(xí)了使用 GROUP BY 子句對多組數(shù)據(jù)進(jìn)行匯總計算刘莹,并返回每個分組的結(jié)果。并實(shí)踐了如何使用 HAVING 子句過濾分組焚刚。