學習SQL【4】-聚合與排序

隨著表中記錄(數據行)的不斷積累,存儲數據逐漸增加,有時我們可能希望計算出這些數據的合計值或者平均值等,這個時候就需要使用SQL語句的匯總操作等方法。

一:對錶進行聚合排序

1:聚合函數

通過SQL對數據進行某種操作或計算時需要使用函數。SQL有五種常用的函數:

● COUNT:計算表中數據的行數(記錄數)。

● SUM:計算表中數值列中數據的合計數。

● AVG:計算表中數值列中數據的平均值。

● MAX:計算表中數值列中數據的最大值。

● MIN:計算表中數值列中數據的最小值。

如上所示,用於匯總的函數成為聚合函數或者聚集函數。接下來,我們仍然使用之前創建的Product表進行函數的學習,Product表的結構和內容如下:

product_id | product_name | product_type | sale_price | purchase_price | regist_date------------+--------------+--------------+------------+----------------+------------- 0001 | T衫 | 衣服 | 1000 | 500 | 2017-09-20 0002 | 打孔器 | 辦公用品 | 500 | 320 | 2017-09-11 0003 | 運動T衫 | 衣服 | 4000 | 2800 | 0004 | 菜刀 | 廚房用具 | 3000 | 2800 | 2017-09-20 0005 | 高壓鍋 | 廚房用具 | 6800 | 5000 | 2017-01-15 0006 | 叉子 | 廚房用具 | 500 | | 2017-09-20 0007 | 擦菜板 | 廚房用具 | 880 | 790 | 2016-04-28 0008 | 圓珠筆 | 辦公用品 | 100 | | 2017-11-11(8 行記錄)

2:計算表中數據的行數

使用COUNT函數時,輸入表的列,就能輸出數據行數:

例如,計算全部數據的行數:

SELECT COUNT(*) FROM Product;

執行結果:

count------- 8(1 行記錄)

COUNT()中的星號,代表全部列的意思。函數的輸入值稱為參數,輸出值稱為返回值。

3:計算NULL之外的數據的行數

SELECT COUNT(purchase_price) FROM Product;

執行結果:

count------- 6(1 行記錄)

對於COUNT函數來說,參數列不同,計算結果也會不同。COUNT(*)會得到包含NULL的數據行數,而COUNT(<列名>)會得到NULL之外的數據行數。

4:計算合計值

計算合計值需要使用SUM函數

例,計算銷售單價的合計值:

SELECT SUM(sale_price) FROM Product;

執行結果:

sum------- 16780(1 行記錄)

例如,計算銷售單價和進貨單價的合計值:

SELECT SUM(sale_price), SUM(purchase_price) FROM Product;

執行結果:

sum | sum-------+------- 16780 | 12210(1 行記錄)

注釋:

聚合函數會將NULL排除在外,但COUNT(*)例外,並不會排除NULL。

5:計算平均值

計算平均值需要使用AVG函數

例,計算銷售單價的平均值:

SELECT AVG(sale_price) FROM Product;

執行結果:

avg----------------------- 2097.5000000000000000(1 行記錄)

例如,計算銷售單價和進貨單價的平均值:

SELECT AVG(sale_price), AVG(purchase_price) FROM Product;

執行結果:

avg | avg-----------------------+----------------------- 2097.5000000000000000 | 2035.0000000000000000(1 行記錄)

6:計算最大值和最小值

想要計算出多條記錄的最大值或最小值,可以分別使用MAX和MIN函數。

例,計算銷售單價的最大值和進貨單價的最小值:

SELECT MAX(sale_price), MIN(purchase_price) FROM Product;

執行結果:

max | min------+----- 6800 | 320(1 行記錄)

例如,計算登記日期的最大值和最小值:

SELECT MAX(regist_date), MIN(regist_date) FROM Product;

執行結果:

max | min------------+------------ 2017-11-11 | 2016-04-28(1 行記錄)

MAX/MIN函數幾乎適用於所有數據類型的列。而SUM/AVG函數只適用於數值類型的列。

7:使用聚合函數刪除重複值(關鍵字DISTINCT)

例,計算除去重複數據後的數據行數:

SELECT COUNT(DISTINCT product_type) FROM Product;

執行結果:

count------- 3(1 行記錄)

想要計算值的種類時,可以在COUNT函數的參數中使用DISTINCT。

在聚合函數的參數中使用DISTINCT,可以刪除重複數據。

二:對錶進行分組

1:GROUP BY子句

使用GROUP BY子句可以像切蛋糕那樣將表分割。GROUP BY子句的語法結構如下:

SELECT <列名1>, <列名2>,... FROM <表名> GROUP BY <列名1>, <列名2>,...;

例如,按照商品種類統計數據行數:

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;

執行結果:

product_type | count--------------+------- 衣服 | 2 辦公用品 | 2 廚房用具 | 4(3 行記錄)

● 在GROUP BY 子句中指定的列稱為聚合鍵。

● 子句的書寫順序(暫定):

SELECT→FROM→ WHERE→ GROUP BY

● SQL子句的順序不能更改,也不能相互替換。

2:聚合鍵中包含NULL的情況

例,按照進貨單價統計數據行數:

SELECT purchase_price, COUNT(*) FROM Product GROUP BY purchase_price;

執行結果:

purchase_price | count----------------+------- | 2 320 | 1 500 | 1 5000 | 1 2800 | 2 790 | 1(6 行記錄)

聚合鍵中包含NULL時,在結果中會以「不確定」行(空行)的形式顯示出來。

3:使用WHERE子句和GROUP BY 子句的執行結果

例,同時使用WHERE子句和GROUP BY子句:

SELECT purchase_price, COUNT(*) FROM Product WHERE product_type = 衣服 GROUP BY purchase_price;

執行結果:

purchase_price | count----------------+------- 500 | 1 2800 | 1(2 行記錄)

4:與聚合函數和GROUP BY 子句有關的常見錯誤

● 使用GROUP BY 子句時,SELECT 子句中不能出現聚合鍵之外的列名。

● 在GROUP BY 子句中不能使用SELECT子句中定義的別名。

● GROUP BY 子句結果的顯示是無序的。

● 只有SLEECT子句、GROUP BY 子句和HAVING子句中能夠使用聚合函數,WHERE 子句中不能使用聚合函數。

三:為聚合結果指定條件

1:HAVING子句

對集合指定條件可以使用HAVING子句。HAVING子句的語法如下:

SELECT <列名1>, <列名2>,... FROM <表名> GROUP BY <列名1>, <列名2>,... HAVING <分組結果對應的條件>;

注釋:

HAVING子句要寫在GROUP BY 子句之後。

例,從按照商品種類進行分組後的結果中,取出「包含的數據行數為2行」的組:

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type HAVING COUNT(*) = 2;

執行結果:

product_type | count--------------+------- 衣服 | 2 辦公用品 | 2(2 行記錄)

不使用HAVING子句的情況

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;

執行結果:

product_type | count--------------+------- 衣服 | 2 辦公用品 | 2 廚房用具 | 4(3 行記錄)

2:HAVING子句的構成要素

HAVING子句中能夠使用的3中要素如下:

● 常數

● 聚合函數

● GROUP BY 子句中 指定的列名(聚合鍵)

3:相比於HAVING子句,更適合於寫在WHERE子句中的條件

我們會發現,有些條件既可以寫在HAVING子句中,也可以寫在WHERE 子句中,而且結果是一樣的。這些條件就是聚合鍵所對應的條件。

例,將條件寫在HAVING 子句中:

SELECT product_type, COUNT(*) FROM Product GROUP BY product_type HAVING product_type = 衣服;

執行結果:

product_type | count--------------+------- 衣服 | 2(1 行記錄)

將條件書寫在WHERE子句中的情況

SELECT product_type, COUNT(*) FROM Product WHERE product_type = 衣服 GROUP BY product_type;

執行結果:

product_type | count--------------+------- 衣服 | 2(1 行記錄)

兩者結果完全相同,但是,從執行速度來講,將條件寫在WHERE 子句中要比寫在HAVING子句中的處理速度要快。所以,聚合鍵所對應的條件應該書寫在WHERE 子句中。

四:對查詢結果進行排序

1:ORDER BY子句

使用ORDER BY 子句可對查詢結果進行排序,ORDER BY子句的語法:

SELECT <列名1>, <列名2>,... FROM <表名> ORDER BY <排列基準1>, <排列基準2>,....;

例,按照銷售單價由低到高(升序)進行排序:

SELECT product_id, product_name, sale_price, purchase_price FROM Product ORDER BY sale_price;

執行結果:

product_id | product_name | sale_price | purchase_price------------+--------------+------------+---------------- 0008 | 圓珠筆 | 100 | 0006 | 叉子 | 500 | 0002 | 打孔器 | 500 | 320 0007 | 擦菜板 | 880 | 790 0001 | T衫 | 1000 | 500 0004 | 菜刀 | 3000 | 2800 0003 | 運動T衫 | 4000 | 2800 0005 | 高壓鍋 | 6800 | 5000(8 行記錄)

● ORDER BY子句中書寫的列名稱為排序鍵。

● ORDER BY 子句通常寫在SELECT語句的末尾。

2:指定升序或降序

降序排列時,可使用DESC關鍵字。

例,按照銷售單價由高到低(降序)進行排序:

SELECT product_id, product_name, sale_price, purchase_price FROM Product ORDER BY sale_price DESC;

執行結果:

product_id | product_name | sale_price | purchase_price------------+--------------+------------+---------------- 0005 | 高壓鍋 | 6800 | 5000 0003 | 運動T衫 | 4000 | 2800 0004 | 菜刀 | 3000 | 2800 0001 | T衫 | 1000 | 500 0007 | 擦菜板 | 880 | 790 0002 | 打孔器 | 500 | 320 0006 | 叉子 | 500 | 0008 | 圓珠筆 | 100 |(8 行記錄)

注釋:

未指定ORDER BY 子句中排列順序時會默認以升序排列。

3:指定多個排序鍵

可以在ORDER BY 子句中指定多個排序鍵,規則是優先使用左側的鍵,如果該列存在相同的值,再接著參考右側的鍵。

例,按照銷售單價和商品編號的升序進行排序:

SELECT product_id, product_name, sale_price, purchase_price FROM Product ORDER BY sale_price, product_id;

執行結果:

product_id | product_name | sale_price | purchase_price------------+--------------+------------+---------------- 0008 | 圓珠筆 | 100 | 0002 | 打孔器 | 500 | 320 0006 | 叉子 | 500 | 0007 | 擦菜板 | 880 | 790 0001 | T衫 | 1000 | 500 0004 | 菜刀 | 3000 | 2800 0003 | 運動T衫 | 4000 | 2800 0005 | 高壓鍋 | 6800 | 5000(8 行記錄)

4:NULL 的排序

例,按照進貨單價的升序進行排序:

SELECT product_id, product_name, sale_price, purchase_price FROM Product ORDER BY purchase_price;

執行結果:

product_id | product_name | sale_price | purchase_price------------+--------------+------------+---------------- 0002 | 打孔器 | 500 | 320 0001 | T衫 | 1000 | 500 0007 | 擦菜板 | 880 | 790 0003 | 運動T衫 | 4000 | 2800 0004 | 菜刀 | 3000 | 2800 0005 | 高壓鍋 | 6800 | 5000 0006 | 叉子 | 500 | 0008 | 圓珠筆 | 100 |(8 行記錄)

如上所示,排序鍵包含NULL時,會在開頭或者末尾進行匯總。

5:幾點關於ORDER BY子句的事項

● 在ORDER BY 子句中可以使用SELECT子句中定義的別名。

● 在ORDER BY 子句中可以使用SLEECT子句中為使用的列和聚合函數。

● 在ORDER BY 子句中不要使用列編號。

路漫漫其修遠兮,吾將上下而求索。

每天學習一點點,每天進步一點點。


推薦閱讀:

OCP-1Z0-051 第十題
《基於oracle學習SQL語言》學習筆記——第三章 單行函數
SQL速覽
SQL默示錄(一)
索引列只要參與了計算, 查詢就會不走索引, 為什麼 MySQL 不對這種情況進行優化?

TAG:SQL | 資料庫 | 自學編程 |