1. 程式人生 > 其它 >SQL基礎-第3章 聚合與排序

SQL基礎-第3章 聚合與排序

3-1 對錶進行聚合查詢

聚合函式

  • COUNT: 計算表中的記錄數(行數)
  • SUM: 計算表中數值列中資料的合計值
  • AVG: 計算表中數值列中資料的平均值
  • MAX: 求出表中任意列中資料的最大值
  • MIN: 求出表中任意列中資料的最小值

計算表中資料的行數

-- 計算全部資料的行數
SELECT COUNT(*)
FROM Product;

計算NULL之外的資料的行數

COUNT(*)會得到包含NULL的資料行數
COUNT(<列名>)會得到NULL之外的資料行數

-- 計算NULL之外的資料行數
SELECT COUNT(purchase_price)
FROM Product;

-- 將包含NULL的列作為引數時, COUNT( *) 和COUNT(<列名>)的結果並不相同
SELECT COUNT(*), COUNT(purchase_price)
FROM Product;

計算合計值

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

-- 計算銷售單價的合計值
SELECT SUM(sale_price)
FROM Product;

-- 計算銷售單價和進貨單價的合計值
SELECT SUM(sale_price), SUM(purchase_price)
FROM Product;

計算平均值

-- 計算銷售單價的平均值
SELECT AVG(sale_price)
FROM Product;

-- 計算銷售單價和進貨單價的平均值
SELECT AVG(sale_price), AVG(purchase_price)
FROM Product;

計算值和小值

MAX/MIN函式幾乎適用於所有資料型別的列。 SUM/AVG函式只適用於數值型別的列。

-- 計算銷售單價的最大值和進貨單價的最小值
SELECT MAX(sale_price), MIN(purchase_price)
FROM Product;

-- 計算登記日期的最大值和最小值
SELECT MAX(regist_date), MIN(regist_date)
FROM Product;

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

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

在聚合函式的引數中使用DISTINCT,可以刪除重複資料。

-- 計算去除重複資料後的資料行數
SELECT COUNT(DISTINCT product_type)
FROM Product;

-- 先計算資料行數再刪除重複資料的結果
SELECT DISTINCT COUNT(product_type)
FROM Product;

-- 使不使用DISTINCT時的動作差異( SUM函式)
SELECT SUM(sale_price), SUM(DISTINCT sale_price)
FROM Product;

3-2 對錶進行分組

GROUP-BY子句

使用GROUP BY子句進行彙總
SELECT <列名1>, <列名2>, <列名3>, ……
FROM <表名>
GROUP BY <列名1>, <列名2>, <列名3>, ……;

GROUP BY 子句的書寫位置也有嚴格要求,一定要寫在 FROM 語句之後(如果有 WHERE 子句的話需要寫在 WHERE 子句之後)

-- 按照商品種類統計資料行數
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;

聚合鍵中包含NULL的情況

聚合鍵中包含NULL時,在結果中會以“不確定”行(空行)的形式表現出來。

-- 按照進貨單價統計資料行數
SELECT purchase_price, COUNT(*)
FROM Product
GROUP BY purchase_price;

使用WHERE子句時GROUP-BY的執行結果

使用WHERE子句和GROUP BY子句進行彙總處理

SELECT <列名1>, <列名2>, <列名3>, ……
FROM <表名>
WHERE
GROUP BY <列名1>, <列名2>, <列名3>, ……;

GROUP BY 和 WHERE 並用時,SELECT 語句的執行順序
FROM → WHERE → GROUP BY → SELECT

-- 同時使用WHERE子句和GROUP BY子句
SELECT purchase_price, COUNT(*)
FROM Product
WHERE product_type = '衣服'
GROUP BY purchase_price;

與聚合函式和GROUP-BY子句有關的常見錯誤

  1. 在SELECT子句中書寫了多餘的列

使用聚合函式時, SELECT 子句中只能存在以下三種元素。

  • 常數
  • 聚合函式
  • GROUP BY子句中指定的列名(也就是聚合鍵)

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

-- 在SELECT子句中書寫聚合鍵之外的列名會發生錯誤
SELECT product_name, purchase_price, COUNT(*)
FROM Product
GROUP BY purchase_price;

#1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'shop.Product.product_name' 
which is not functionally dependent on columns in GROUP BY clause
  1. 在GROUP BY子句中寫了列的別名
    這樣的寫法在其他 DBMS 中並不是通用的,因此請大家不要使用
-- GROUP BY子句中使用列的別名會引發錯誤
SELECT product_type AS pt, COUNT(*)
FROM Product
GROUP BY pt;
  1. GROUP BY子句的結果能排序嗎
    GROUP BY子句結果的顯示是無序的

  2. 在WHERE子句中使用聚合函式

-- 按照商品種類統計資料行數
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;

-- 在WHERE子句中使用聚合函式會引發錯誤
SELECT product_type, COUNT(*)
FROM Product
WHERE COUNT(*) = 2
GROUP BY product_type;
-- ERROR: 不能在WHERE子句中使用聚合

只有SELECT子句和HAVING子句(以及ORDER BY子句)中能夠使用聚合函式。

-- DISTINCT和GROUP BY能夠實現相同的功能
SELECT DISTINCT product_type
FROM Product;

SELECT product_type
FROM Product
GROUP BY product_type;

3-3 為聚合結果指定條件

HAVING子句

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

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

-- 從按照商品種類進行分組後的結果中,取出“包含的資料行數為2行”的組
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING COUNT(*) = 2;

-- 不使用HAVING子句的情況
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;

HAVING子句的構成要素

  • 常數
  • 聚合函式
  • GROUP BY子句中指定的列名(即聚合鍵)
-- HAVING子句的不正確使用方法
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING product_name = '圓珠筆';

ERROR: 列"product,product_name"必須包含在GROUP BY子句當中,或者必須在聚合函式中使用

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

-- 將條件書寫在HAVING子句中的情況
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
HAVING product_type = '衣服';
-- 將條件書寫在WHERE子句中的情況
SELECT product_type, COUNT(*)
FROM Product
WHERE product_type = '衣服'
GROUP BY product_type;
  • WHERE 子句 = 指定行所對應的條件
  • HAVING 子句 = 指定組所對應的條件

WHERE 子句更具速度優勢的另一個理由是,可以對 WHERE 子句指定條件所對應的列建立索引,這樣也可以大幅提高處理速度

3-4 對查詢結果進行排序

ORDER-BY子句

SELECT <列名1>, <列名2>, <列名3>, ……
FROM <表名>
ORDER BY <排序基準列1>, <排序基準列2>, ……

子句的書寫順序

  1. SELECT 子句 → 2. FROM 子句 → 3. WHERE 子句 → 4. GROUP BY 子句 → 5. HAVING 子句 → 6. ORDER BY 子句
-- 顯示商品編號、商品名稱、銷售單價和進貨單價的SELECT語句
SELECT product_id, product_name, sale_price, purchase_price FROM Product;

-- 按照銷售單價由低到高(升序)進行排列
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price;

指定升序或降序

未指定ORDER BY子句中排列順序時會預設使用升序進行排列

-- 按照銷售單價由高到低(降序)進行排列
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price DESC;

指定多個排序鍵

-- 按照銷售單價和商品編號的升序進行排序
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price, product_id;

NULL的順序

排序鍵中包含NULL時,會在開頭或末尾進行彙總。

-- 按照進貨單價的升序進行排列
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY purchase_price;

在排序鍵中使用顯示用的別名

一定要記住 SELECT 子句的執行順序在 GROUP BY 子句之後, ORDER BY 子句之前

-- ORDER BY子句中可以使用列的別名
SELECT product_id AS id, product_name, sale_price AS sp, purchase_price
FROM Product
ORDER BY sp, id;

ORDER-BY子句中可以使用的列

在ORDER BY子句中可以使用SELECT子句中未使用的列和聚合函式。

-- SELECT子句中未包含的列也可以在ORDER BY子句中使用
SELECT product_name, sale_price, purchase_price
FROM Product
ORDER BY product_id;

-- ORDER BY子句中也可以使用聚合函式
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type
ORDER BY COUNT(*);

不要使用列編號

  • 程式碼閱讀起來比較難
  • 排序功能將來會被刪除
-- 通過列名指定
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY sale_price DESC, product_id;
-- 通過列編號指定
SELECT product_id, product_name, sale_price, purchase_price
FROM Product
ORDER BY 3 DESC, 1;

練習題

3.1 請指出下述 SELECT 語句中所有的語法錯誤。

-- 本SELECT語句中存在錯誤。
SELECT product_id, SUM(product_name)
FROM Product
GROUP BY product_type
WHERE regist_date > '2009-09-01';
  1. 使用了字元型別的列(product_name)作為 SUM 函式的引數。
    SUM 函式只能使用數值型別的列作為引數。

  2. WHERE 子句寫在了 GROUP BY 子句之後。
    WHERE 子句必須寫在 GROUP BY 子句之前。

  3. SELECT 子句中存在 GROUP BY 子句中未指定的列(product_id)。
    使用 GROUP BY 子句時,書寫在 SELECT 子句中的列有很多限制。 GROUP BY子句中未指定的列不能書寫在 SELECT 子句之中。

3.2 請編寫一條 SELECT 語句,求出銷售單價( sale_price 列)合計值是進貨單價( purchase_price 列)合計值 1.5 倍的商品種類。執行結果如下所示。

product_type sum sum
衣服 5000 3300
辦公用品 600 320
SELECT product_type, sum(sale_price), sum(purchase_price)
FROM Product
GROUP BY product_type
HAVING sum(sale_price) > sum(purchase_price) * 1.5
ORDER BY sum(sale_price) DESC;

3.3 此前我們曾經使用 SELECT 語句選取出了 Product( 商品) 表中的全部記錄。當時我們使用了 ORDER BY 子句來指定排列順序,但現在已經無法記起當時如何指定的了。請根據下列執行結果,思考 ORDER BY 子句的內容。

執行結果

product_id product_name product_type sale_price purchase_price regist_date
0003 運動T恤 衣服 4000 2800
0008 圓珠筆 辦公用品 100 2009-11-11
0006 叉子 廚房用具 500 2009-09-20
0001 T恤衫 衣服 1000 500 2009-09-20
0004 菜刀 廚房用具 3000 2800 2009-09-20
0002 打孔器 辦公用品 500 320 2009-09-11
0005 高壓鍋 廚房用具 6800 5000 2009-01-15
0007 擦菜板 廚房用具 880 790 2008-04-28
SELECT product_id, product_name, product_type, sale_price, purchase_price, regist_date
FROM Product
ORDER BY regist_date DESC, sale_price;