學習重點
使用聚合函數對表中的列進行計算合計值或者平均值等的匯總操作。
通常,聚合函數會對
NULL
以外的對象進行匯總。但是只有COUNT
函數例外,使用COUNT(*)
可以查出包含NULL
在內的全部數據的行數。使用
DISTINCT
關鍵字刪除重復值。
一、聚合函數
通過 SQL 對數據進行某種操作或計算時需要使用函數。例如,計算表中全部數據的行數時,可以使用 COUNT
函數。該函數就是使用 COUNT(計數)
來命名的。除此之外,SQL 中還有很多其他用於匯總的函數,請大家先記住以下 5 個常用的函數。
KEYWORD
函數
COUNT
函數
COUNT
:計算表中的記錄數(行數)
SUM
:計算表中數值列中數據的合計值
AVG
:計算表中數值列中數據的平均值
MAX
:求出表中任意列中數據的最大值
MIN
:求出表中任意列中數據的最小值
如上所示,用於匯總的函數稱為聚合函數或者聚集函數,本教程中統稱為聚合函數。所謂聚合,就是將多行匯總為一行。實際上,所有的聚合函數都是這樣,輸入多行輸出一行。
KEYWORD
聚合函數
聚集函數
聚合
接下來,本文將繼續使用在 表的創建 中創建的 Product 表(圖 1)來學習函數的使用方法。

圖 1 Product 表的內容
二、計算表中數據的行數
首先,我們以 COUNT
函數為例讓大家對函數形成一個初步印象。函數這個詞,與我們在學校數學課上學到的意思是一樣的,就像是輸入某個值就能輸出相應結果的盒子一樣 [1]。
使用 COUNT
函數時,輸入表的列,就能夠輸出數據行數。如圖 2 所示,將表中的列放入名稱為 COUNT
的盒子中,咔嗒咔嗒地進行計算,咕咚一下行數就出來了……就像自動售貨機那樣,很容易理解吧。

圖 2 COUNT 函數的操作演示圖
接下來讓我們看一下 SQL 中的具體書寫方法。COUNT
函數的語法本身非常簡單,像代碼清單 1 那樣寫在 SELECT
子句中就可以得到表中全部數據的行數了。
代碼清單 1 計算全部數據的行數
執行結果
COUNT()
中的星號,我們在 SELECT 語句基礎 中已經學過,代表全部列的意思。COUNT
函數的輸入值就記述在其后的括號中。
此處的輸入值稱為參數或者 parameter,輸出值稱為返回值。這些稱謂不僅本教程中會使用,在多數編程語言中使用函數時都會頻繁出現,請大家牢記。
KEYWORD
參數(parameter)
返回值
三、計算 NULL
之外的數據的行數
想要計算表中全部數據的行數時,可以像 SELECT COUNT(*)~
這樣使用星號。如果想得到 purchase_price
列(進貨單價)中非空行數的話,可以像代碼清單 2 那樣,通過將對象列設定為參數來實現。
代碼清單 2 計算 NULL
之外的數據行數
SELECT COUNT(purchase_price)
FROM Product;
執行結果
count
-------
6
此時,如圖 1 所示,purchase_price
列中有兩行數據是 NULL
,因此並不應該計算這兩行。對於 COUNT
函數來說,參數列不同計算的結果也會發生變化,這一點請大家特別注意。為了有助於大家理解,請看如下這個只包含 NULL
的表的極端例子。

圖 3 只包含 NULL 的表
我們來看一下針對上述表,將星號(*
)和列名作為參數傳遞給 COUNT
函數時所得到的結果(代碼清單 3)。
代碼清單 3 將包含 NULL
的列作為參數時,COUNT(*)
和 COUNT(<列名>)
的結果並不相同
SELECT COUNT(*), COUNT(col_1)
FROM NullTbl;
執行結果
如上所示,即使對同一個表使用 COUNT
函數,輸入的參數不同得到的結果也會不同。由於將列名作為參數時會得到 NULL
之外的數據行數,所以得到的結果是 0 行。
該特性是 COUNT
函數所特有的,其他函數並不能將星號作為參數(如果使用星號會出錯)。
法則 1
COUNT
函數的結果根據參數的不同而不同。COUNT(*)
會得到包含NULL
的數據行數,而COUNT(<列名>)
會得到NULL
之外的數據行數。
四、計算合計值
接下來我們學習其他 4 個聚合函數的使用方法。這些函數的語法基本上與 COUNT
函數相同,但就像我們此前所說的那樣,在這些函數中不能使用星號作為參數。
首先,我們使用計算合計值的 SUM
函數,求出銷售單價的合計值(代碼清單 4)。
KEYWORD
SUM
函數
代碼清單 4 計算銷售單價的合計值
SELECT SUM(sale_price)
FROM Product;
執行結果
sum
------
16780
得到的結果 16780 日元,是所有銷售單價(sale_price
列)的合計,與下述計算式的結果相同。
接下來,我們將銷售單價和進貨單價(purchase_price
列)的合計值一起計算出來(代碼清單 5)。
代碼清單 5 計算銷售單價和進貨單價的合計值
SELECT SUM(sale_price), SUM(purchase_price)
FROM Product;
執行結果
這次我們通過 SUM(purchase_price)
將進貨單價的合計值也一起計算出來了,但有一點需要大家注意。具體的計算過程如下所示。
大家都已經注意到了吧,與銷售單價不同,進貨單價中有兩條不明數據 NULL
。對於 SUM
函數來說,即使包含 NULL
,也可以計算出合計值。還記得 算術運算符和比較運算符 中內容的讀者可能會產生如下疑問。
“四則運算中如果存在 NULL
,結果一定是 NULL
,那此時進貨單價的合計值會不會也是 NULL
呢?”
有這樣疑問的讀者思維很敏銳,但實際上這兩者並不矛盾。從結果上說,所有的聚合函數,如果以列名為參數,那么在計算之前就已經把 NULL
排除在外了。因此,無論有多少個 NULL
都會被無視。這與“等價為 0”並不相同 [2]。
因此,上述進貨單價的計算表達式,實際上應該如下所示。
法則 2
聚合函數會將
NULL
排除在外。但COUNT(*)
例外,並不會排除NULL
。
五、計算平均值
接下來,我們練習一下計算多行數據的平均值。為此,我們需要使用 AVG
函數,其語法和 SUM
函數完全相同(代碼清單 6)。
KEYWORD
AVG
函數
代碼清單 6 計算銷售單價的平均值
SELECT AVG(sale_price)
FROM Product;
執行結果
avg
----------------------
2097.5000000000000000
平均值的計算式如下所示。
( 值的合計 )/( 值的個數 ) 就是平均值的計算公式了。下面我們也像使用 SUM
函數那樣,計算一下包含 NULL
的進貨單價的平均值(代碼清單 7)。
代碼清單 7 計算銷售單價和進貨單價的平均值
SELECT AVG(sale_price), AVG(purchase_price)
FROM Product;
執行結果
計算進貨單價平均值的情況與 SUM
函數相同,會事先刪除 NULL
再進行計算,因此計算式如下所示。
需要注意的是分母是 6 而不是 8,減少的兩個也就是那兩條 NULL
的數據。
但是有時也想將 NULL
作為 0 進行計算。
但是有時也想將 NULL
作為 0 進行計算,具體的實現方式請參 各種各樣的函數。
六、計算最大值和最小值
想要計算出多條記錄中的最大值或最小值,可以分別使用 MAX
和 MIN
函數,它們是英語 maximam(最大值)和 minimum(最小值)的縮寫,很容易記住。
KEYWORD
MAX
函數
MIN
函數
這兩個函數的語法與 SUM
的語法相同,使用時需要將列作為參數(代碼清單 8)。
代碼清單 8 計算銷售單價的最大值和進貨單價的最小值
SELECT MAX(sale_price), MIN(purchase_price)
FROM Product;
執行結果
如圖 3 所示,我們取得了相應的最大值和最小值。
但是,MAX/MIN
函數和 SUM/AVG
函數有一點不同,那就是 SUM/AVG
函數只能對數值類型的列使用,而 MAX/MIN
函數原則上可以適用於任何數據類型的列。例如,對圖 1 中日期類型的列 regist_date
使用 MAX/MIN
函數進行計算的結果如下所示(代碼清單 9)。
代碼清單 9 計算登記日期的最大值和最小值
SELECT MAX(regist_date), MIN(regist_date)
FROM Product;
執行結果
剛剛我們說過 MAX/MIN
函數適用於任何數據類型的列,也就是說,只要是能夠排序的數據,就肯定有最大值和最小值,也就能夠使用這兩個函數。對日期來說,平均值和合計值並沒有什么實際意義,因此不能使用 SUM/AVG
函數。這點對於字符串類型的數據也適用,字符串類型的數據能夠使用 MAX/MIN
函數,但不能使用 SUM/AVG
函數。
法則 3
MAX/MIN
函數幾乎適用於所有數據類型的列。SUM/AVG
函數只適用於數值類型的列。
七、使用聚合函數刪除重復值(關鍵字 DISTINCT
)
接下來我們考慮一下下面這種情況。
在圖 1 中我們可以看到,商品種類(product_type
列)和銷售單價(sale_price
列)的數據中,存在多行數據相同的情況。
例如,拿商品種類來說,表中總共有 3 種商品共 8 行數據,其中衣服 2 行,辦公用品 2 行,廚房用具 4 行。如果想要計算出商品種類的個數,怎么做比較好呢?刪除重復數據然后再計算數據行數似乎是個不錯的辦法。實際上,在使用 COUNT
函數時,將 SELECT 語句基礎 中介紹過的 DISTINCT
關鍵字作為參數,就能得到我們想要的結果了(代碼清單 10)。
KEYWORD
DISTINCT
關鍵字
代碼清單 10 計算去除重復數據后的數據行數
SELECT COUNT(DISTINCT product_type)
FROM Product;
執行結果
count
-------
3
請注意,這時 DISTINCT
必須寫在括號中。這是因為必須要在計算行數之前刪除 product_type
列中的重復數據。如果像代碼清單 11 那樣寫在括號外的話,就會先計算出數據行數,然后再刪除重復數據,結果就得到了 product_type
列的所有行數(也就是 8)。
代碼清單 11 先計算數據行數再刪除重復數據的結果
SELECT DISTINCT COUNT(product_type)
FROM Product;
執行結果
count
-------
8
法則 4
想要計算值的種類時,可以在
COUNT
函數的參數中使用DISTINCT
。
不僅限於 COUNT
函數,所有的聚合函數都可以使用 DISTINCT
。下面我們來看一下使用 DISTINCT
和不使用 DISTINCT
時 SUM
函數的執行結果(代碼清單 12)。
代碼清單 12 使不使用 DISTINCT
時的動作差異(SUM
函數)
SELECT SUM(sale_price), SUM(DISTINCT sale_price)
FROM Product;
執行結果
左側是未使用 DISTINCT
時的合計值,和我們之前計算的結果相同,都是 16780 日元。右側是使用 DISTINCT
后的合計值,比之前的結果少了 500 日元。這是因為表中銷售單價為 500 日元的商品有兩種——“打孔器”和“叉子”,在刪除重復數據之后,計算對象就只剩下一條記錄了。
法則 5
在聚合函數的參數中使用
DISTINCT
,可以刪除重復數據。
請參閱
(完)