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()函數有兩種使用方式:
- 使用COUNT(*)對表中行的數目進行計數,不管表列中包含的是空值NULL還是非空值。
- 使用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子句前,需要知道一些重要的規定。
- GROUP BY子句可以包含任意數目的列,因而可以對分組進行嵌套,更細致地進行數據分組。
- 如果在GROUP BY子句中嵌套了分組,數據將在最后指定的分組上進行匯總。換句話說,在建立分組時,指定的所有列都一起計算,不能從個別的列取回數據。
- GROUP BY子句中列出的每一列都必須是檢索列或有效的表達式(但不能是聚集函數)。如果在SELECT中使用表達式,則必須在GROUP BY子句中指定相同的表達式,不能使用別名。
- 大多數SQL實現不允許GROUP BY列帶有長度可變的數據類型(如文本或備注型字段)。
- 除聚集計算語句外,SELECT語句中的每一列都必須在GROUP BY子句中給出。
- 如果分組列中包含具有NULL值的行,則NULL將作為一個分組返回。如果列中有多行NULL值,它們將分為一組。
- 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 | 輸出排序順序 | 否 |
如果您發現文中有不清楚或者有問題的地方,請在下方評論區留言,我會根據您的評論,更新文中相關內容,謝謝!