Minghsin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

明新科大 AQI 70 24°C PM2.5 19
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 06

查詢資料

SELECT、WHERE、ORDER BY、LIMIT、DISTINCT、聚合與 GROUP BY
Interaction實作 30 minute(s)

Learning Objectives

  • 用 SELECT 取出需要的欄位,用 WHERE 篩選資料列
  • 用 ORDER BY 排序、用 LIMIT 取出部分結果,說明沒有 ORDER BY 時列的順序不保證
  • 使用 DISTINCT、欄位別名與表格別名
  • 用 COUNT 等聚合函式與 GROUP BY 分組統計,分辨 WHERE 與 HAVING
  • 說出 SELECT 各子句實際的執行順序:FROM、WHERE、GROUP BY、HAVING、SELECT、ORDER BY、LIMIT

本課使用的資料庫

本課沿用第 04、05 課建立的 employee 資料庫,記錄一家顧問公司的部門、員工、技能、客戶與派工:

表格 內容
department 部門:departmentID、name
employee 員工:employeeID、name、job、departmentID(外鍵,指向部門)
employeeSkills 員工技能:employeeID、skill,一位員工可以有多項技能
client 客戶:clientID、name、address、contactPerson、contactNumber
assignment 派工:哪位員工在哪一天替哪個客戶工作幾小時

下面的範例在執行前,資料庫裡已經有這些表格和資料。播放時,右邊會顯示資料庫裡的表格, 左邊顯示「這一步」的中間結果:一個 SELECT 會拆成好幾步,讓你看到每個子句做了什麼。

SELECT 與 WHERE

最簡單的查詢取出整張表格:

SELECT * FROM employee;

* 代表所有欄位。實務上建議只列出需要的欄位,傳回的資料比較少,表格之後增加欄位時,程式也不會受到影響:

SELECT name, job FROM employee;

WHERE 加上條件,只留下符合條件的資料列:

SELECT name, job
FROM employee
WHERE job = 'Programmer';
  • 字串用單引號括起來。比較時不分大小寫:'programmer' 也會符合,這是 MySQL 8 預設的定序 utf8mb4_0900_ai_ci 的規則(ci 是 case-insensitive)
  • 比較運算子:=、<>(或 !=)、<、<=、>、>=
  • 多個條件用 AND、OR 組合,NOT 取相反;混合使用時加上括號,避免誤解運算順序
  • 一個敘述可以寫成很多行,以分號 ; 結束

SELECT 與 WHERE 的執行過程

第二個查詢會分成三步:FROM 先把整張 employee 讀進來,WHERE 逐列檢查條件(畫刪除線的列被濾掉),最後 SELECT 只留下 name 和 job 兩個欄位。右邊表格裡淺藍色的列,是這個查詢讀到的資料。

ORDER BY 與 LIMIT

沒有 ORDER BY 時,資料列的順序是不保證的。 InnoDB 通常依主鍵的順序讀取, 但如果查詢只用到某個索引的欄位,MySQL 會改讀那個索引,順序就跟著改變。需要固定順序,一定要寫 ORDER BY:

SELECT * FROM employee
ORDER BY job ASC, name DESC;   -- 先依 job 由小到大,job 相同時依 name 由大到小

ASC 是遞增(預設,可以省略),DESC 是遞減。字串依定序比較:不分大小寫,數字排在字母前面。

LIMIT 只取出部分結果,常用在分頁:

SELECT * FROM employeeSkills LIMIT 5;      -- 前 5 列
SELECT * FROM employeeSkills LIMIT 5, 3;   -- 跳過 5 列,再取 3 列
SELECT * FROM employeeSkills LIMIT 3 OFFSET 5;   -- 和上一行相同

LIMIT 是在排序之後才取,所以「前 3 名」要先 ORDER BY 再 LIMIT 3。

排序之後再取出部分結果

第一個查詢觀察 ORDER BY 的兩層排序:DBA 排在 Programmer 前面,兩位 Programmer 再依姓名由大到小。第二個查詢的 LIMIT 那一步,畫刪除線的列是沒有被取出的:跳過前 2 列,取接下來的 3 列。

想一想:WHERE、ORDER BY 與 LIMIT

1.

employee 有 4 位員工,其中 2 位的 job 是 Programmer。下面的查詢傳回幾列?

SELECT name FROM employee WHERE job = 'programmer';
2.

要找出 employeeID 最大的兩位員工,哪一個寫法正確?

3.

下面的查詢會傳回幾列?

SELECT * FROM employeeSkills LIMIT 6, 5;

(employeeSkills 共有 8 列)

第 1 次作答

DISTINCT 與別名

DISTINCT 去掉重複的結果列:

SELECT DISTINCT job FROM employee;            -- 每種職稱只出現一次
SELECT COUNT(DISTINCT job) FROM employee;     -- 有幾種不同的職稱

欄位別名用 AS 替結果欄位取名字,AS 可以省略;表格別名讓欄位名稱寫起來比較短,第 07 課的多表查詢會大量使用:

SELECT name AS employeeName FROM employee;
SELECT name employeeName FROM employee;       -- 省略 AS
SELECT e.name FROM employee AS e;             -- 表格別名
SELECT employee.name FROM employee;           -- 完整寫出表格名稱

定義了表格別名之後,同一個查詢裡就要用別名,不能再寫原本的表格名稱。

聚合函式與 GROUP BY

聚合函式把很多列算成一個值:

函式 作用
COUNT(*) 列數
COUNT(欄位) 這個欄位不是 NULL 的列數
SUM(欄位)、AVG(欄位) 加總、平均(忽略 NULL)
MIN(欄位)、MAX(欄位) 最小值、最大值

GROUP BY 先把資料列依某個欄位分組,聚合函式再對每一組計算一次:

SELECT departmentID, COUNT(*) AS n
FROM employee
GROUP BY departmentID;          -- 每個部門有幾位員工

要篩選分組之後的結果,用 HAVING;WHERE 是在分組之前篩選資料列,所以 WHERE 裡不能用聚合函式:

SELECT job, COUNT(*) AS n
FROM employee
WHERE departmentID = 128        -- 分組前:只看部門 128 的員工
GROUP BY job
HAVING n >= 2;                  -- 分組後:只留下人數至少 2 的職稱

MySQL 8 預設開啟 ONLY_FULL_GROUP_BY:SELECT 清單裡沒有放進聚合函式的欄位,必須寫在 GROUP BY 裡。 例如 SELECT name, COUNT(*) FROM employee GROUP BY job; 會出現 ERROR 1055,因為同一個職稱有好幾位員工,MySQL 不知道要顯示哪一個 name。

分組統計的執行順序

GROUP BY 那一步,同一組的列左邊標著同一種顏色。第二個查詢依序經過 FROM、WHERE、GROUP BY、HAVING、SELECT、ORDER BY,注意 SELECT 是在 HAVING 之後才算出 n,但 MySQL 允許 HAVING 先使用這個別名。

想一想:WHERE、GROUP BY 與 HAVING

1.

SELECT 的各個子句,實際執行的順序是哪一個?

2.

下面的查詢會傳回什麼?

SELECT COUNT(DISTINCT job) FROM employee;
3.

想找出「技能數量至少 3 項」的員工編號,條件應該寫在哪裡?

SELECT employeeID, COUNT(*) AS n FROM employeeSkills
GROUP BY employeeID
______ n >= 3;
第 1 次作答

動手寫:每位員工的技能數

請查詢 employeeSkills,列出每位員工的 employeeID 與技能數量(欄位名稱取為 skills),依技能數量由多到少排序,數量相同時依 employeeID 由小到大。

你的輸出
預期輸出

重點整理

子句 作用 執行順序
FROM 資料從哪張表格來 1
WHERE 篩選資料列(不能用聚合函式) 2
GROUP BY 分組 3
HAVING 篩選分組後的結果 4
SELECT 算出要顯示的欄位、DISTINCT 去重複 5
ORDER BY 排序(可以使用 SELECT 的別名) 6
LIMIT 取出部分結果 7
  • 沒有 ORDER BY 時資料列的順序不保證
  • 字串比較預設不分大小寫
  • MySQL 8 的 ONLY_FULL_GROUP_BY:沒有聚合的欄位必須出現在 GROUP BY

下一課把多張表格連起來查詢:哪位員工在哪個部門、哪個客戶由誰負責。

這一課完成了!
Next lesson:進階查詢
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。