內容已複查
35 分鐘 · 6 張概念卡 · 6 題對應考古題

SQL 查詢:從條件篩選到分組與 JOIN

本頁為依教材與考古題整理的原創摘要;考古題答案經技術覆核,但不是官方答案。

第一次接觸也沒關係

這堂先懂這些詞

先記住白話意思,不必急著背英文。看到正文時,再把正式名稱接回來。

布林邏輯

也會看到:Boolean logic、AND、OR、NOT

只用真與假來組合條件與決策的邏輯系統。

生活例子:
門禁規則可以是「有卡 AND 密碼正確」才開門。
別搞混:
AND、OR 是邏輯關係,不等同日常語言中模糊的「和/或」。

分組彙總

也會看到:GROUP BY、aggregate、aggregation、SUM、COUNT

先按類別分組,再對每組計算總和、筆數或平均。

生活例子:
把每日訂單按門市分組後,計算各門市總營業額。
別搞混:
WHERE 篩原始列,HAVING 通常篩分組後的結果,兩者層次不同。

WHERE 與 HAVING

也會看到:WHERE、HAVING、SELECT

WHERE 在分組前篩選資料列;HAVING 在分組彙總後篩選群組。

生活例子:
先挑出台北訂單像 WHERE,再只保留總額超過一萬元的店家像 HAVING。
別搞混:
沒有分組語境時不要因為條件含 COUNT 就隨意把 WHERE 與 HAVING 交換。

資料表連接

也會看到:JOIN、INNER JOIN、LEFT JOIN、表格連接

依共同欄位把多張表中相關的列組合起來查詢。

生活例子:
用會員編號把訂單表與會員姓名表拼成完整清單。
別搞混:
JOIN 不等於把兩表全部排列組合;連接條件會決定配對。

以可重現的小型資料表練習 CREATE TABLE、SELECT、WHERE、COUNT、DISTINCT、GROUP BY、HAVING 與 JOIN。重點是依 SQL 的處理層次判斷條件放置位置,並用括號消除 AND/OR 的優先順序歧義。對應考古題答案均為非官方技術覆核。

先抓住這幾件事

  • 寫出基本 CREATE TABLE 與 SELECT-FROM-WHERE 語句。
  • 使用括號正確組合 AND 與 OR 條件。
  • 區分 COUNT、DISTINCT、GROUP BY 與 HAVING 的用途。
  • 依 related columns 使用 JOIN 組合多個 tables。

先想像這個場景

替活動主辦人整理報名名單

主辦人交給你 Customers 與 Orders 兩份表格,要求找出台灣的台北或高雄參加者、統計每個國家的人數,再把訂單配回姓名。你不需要逐列告訴資料庫怎麼翻資料,只要清楚描述要哪些欄位、哪些列、如何分組,以及兩張表用哪個欄位配對。

先別急著往下看,花十秒想一想:

條件寫成 Country='Taiwan' AND City='Taipei' OR City='Kaohsiung',日本的 Kaohsiung 紀錄會不會被選進來?你會如何加括號表達真正需求?

把故事換成電腦語言

生活中的角色對應到技術概念
在整理需求上明列最後要抄出的欄位SELECT 指定查詢輸出的 expressions
逐筆檢查國家與城市,只留下符合條件的報名者WHERE 在 grouping 前過濾 individual rows
依國家把報名者分成不同疊,再計算每疊人數GROUP BY 形成 groups,aggregate function 對每組彙整
完成分疊後,只保留人數至少兩人的國家HAVING 依 aggregate 結果篩選 groups
用 CustomerID 把訂單名單配回客戶姓名JOIN 依 join condition 組合不同 tables 的相關 rows

題目出現這些字,先想到

  • 建立含 columns 的資料表用 CREATE TABLE,不是 CREATE DATABASE,也不是不存在的 BUILD TABLE。
  • AND 優先於 OR;遇到『A 且(B 或 C)』直接用括號,避免 C 脫離 A 的限制。
  • COUNT(*) 數 rows;COUNT(column) 忽略該欄 NULL;COUNT(DISTINCT column) 再去除重複值。
  • 單列條件放 WHERE,aggregate 後的群組條件放 HAVING;跨表配對要寫正確 JOIN ... ON 條件。

1.Table Definition 與基本查詢骨架

SQL(Structured Query Language)是操作關聯式資料庫的標準語言,分為幾大類:DDL(Data Definition Language,定義表結構)、DML(Data Manipulation Language,查詢和修改資料)、DCL(Data Control Language,權限管理)。考古題以 DML 的 SELECT 查詢最常考。 【DDL 基本語法】 CREATE TABLE Student ( student_id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, dept_id INT REFERENCES Department(dept_id), gpa DECIMAL(3,2) ); 這定義了一個 Student 表,student_id 是 primary key(自動 NOT NULL),dept_id 是 foreign key 引用 Department 表。 【SELECT 查詢骨架】一個完整的 SELECT 語句的執行順序(注意和書寫順序不同): (1) FROM — 確定資料來源的表 (2) WHERE — 過濾個別 row (3) GROUP BY — 分組 (4) HAVING — 過濾分組 (5) SELECT — 選擇要輸出的欄位 (6) ORDER BY — 排序結果 (7) LIMIT — 限制輸出數量 【基本查詢範例】 SELECT name, gpa FROM Student WHERE gpa >= 3.5 ORDER BY gpa DESC; 意思是:從 Student 表中選出 GPA ≥ 3.5 的學生,依 GPA 由高到低排序,只輸出姓名和 GPA。 【考試連結】考古題最常考的 SQL 題型:(1) 給定表結構和查詢需求,寫出 SQL。(2) 給定 SQL,判斷輸出結果。(3) 找出 SQL 中的語法錯誤。最常見的陷阱是搞混 WHERE 和 HAVING — WHERE 過濾個別 row(在 GROUP BY 之前),HAVING 過濾分組後的結果(在 GROUP BY 之後)。

  • CREATE TABLE Customers (CustomerID INT, CustomerName VARCHAR(255)); 是基本 DDL 形式。
  • SELECT * 代表選取目前來源中所有 columns,不等於不過濾 rows。
  • SQL keywords 常不區分大小寫,但字串 literal 與 identifier 規則依 DBMS 而異。
  • DDL 定義結構;SELECT 屬查詢,兩者目的不同。

2.WHERE、AND/OR 與括號

WHERE 子句用來過濾不符合條件的 row,只留下條件為 true 的 row。WHERE 在 GROUP BY 之前執行,所以它過濾的是個別 row,不是分組。 【比較運算子】=(等於)、<>(不等於)、<、>、<=、>=。字串比較用單引號:WHERE country = 'Taiwan'。NULL 值不能用 = 比較 — 必須用 IS NULL 或 IS NOT NULL。 【邏輯運算子優先順序】NOT > AND > OR。這意味著 WHERE A OR B AND C 等價於 WHERE A OR (B AND C),不是 (A OR B) AND C。如果要先算 OR,必須加括號:WHERE (A OR B) AND C。 【具體範例】要找出台北或高雄的資管系學生: ✓ WHERE (city = 'Taipei' OR city = 'Kaohsiung') AND dept = 'MIS' ✗ WHERE city = 'Taipei' OR city = 'Kaohsiung' AND dept = 'MIS' 第二種寫法因為 AND 優先於 OR,等價於:city = 'Taipei' OR (city = 'Kaohsiung' AND dept = 'MIS') — 會選出所有台北人(不限科系)加上高雄的資管系學生,不是預期結果。 【其他常用條件】 • BETWEEN a AND b:包含兩端,等價於 >= a AND <= b • IN (v1, v2, v3):等價於 = v1 OR = v2 OR = v3 • LIKE '%pattern%':模糊比對,% 匹配任意長度字串,_ 匹配單一字元 • EXISTS (subquery):子查詢有結果時為 true 【考試連結】最常考的陷阱就是 AND/OR 優先順序。考古題 106-19 涉及 port 範圍判斷,核心就是條件組合的邏輯正確性。另一個常見陷阱是 NULL 的三值邏輯:NULL = NULL 的結果不是 true,而是 unknown。

  • 正確邏輯是 Country='Taiwan' AND (City='Taipei' OR City='Kaohsiung')。
  • 省略括號可能把其他 country 的 Kaohsiung rows 一併選入。
  • 逗號不能取代 WHERE 中的 Boolean operators。
  • 可用 IN ('Taipei','Kaohsiung') 表達同一組離散候選值。

SQL:WHERE city = 'Taipei' OR city = 'Kaohsiung' AND dept = 'MIS',會選出?

3.Aggregate、DISTINCT、GROUP BY 與 HAVING

Aggregate functions(聚合函數)對一組 row 計算出單一值:COUNT(計數)、SUM(加總)、AVG(平均)、MAX(最大)、MIN(最小)。 【DISTINCT】去除重複值。SELECT DISTINCT city FROM Student 只輸出不重複的城市名。COUNT(DISTINCT dept_id) 計算不同部門的數量。 【GROUP BY】把 row 按照指定欄位分組,然後對每組分別套用 aggregate function。例如: SELECT dept_id, COUNT(*) AS student_count, AVG(gpa) AS avg_gpa FROM Student GROUP BY dept_id; 這會按 dept_id 分組,算出每個系所的學生數和平均 GPA。重要規則:SELECT 子句中,除了 aggregate function 之外的所有欄位,都必須出現在 GROUP BY 中。SELECT dept_id, name, COUNT(*) FROM Student GROUP BY dept_id 是錯誤的 — name 沒有在 GROUP BY 中。 【HAVING vs WHERE】WHERE 在 GROUP BY 之前過濾個別 row,HAVING 在 GROUP BY 之後過濾分組。例如: SELECT dept_id, AVG(gpa) FROM Student WHERE gpa IS NOT NULL -- 先排除 GPA 為空的學生 GROUP BY dept_id HAVING AVG(gpa) >= 3.0; -- 再排除平均 GPA < 3.0 的系所 WHERE 中不能使用 aggregate function(因為 WHERE 在分組前執行,此時還沒有分組結果可計算)。HAVING 中可以使用 aggregate function。 【考試連結】最常考的題型:(1) WHERE 和 HAVING 的差異。(2) SELECT 中的欄位是否都在 GROUP BY 中。(3) COUNT(*) vs COUNT(column) 的差異 — COUNT(*) 計算所有 row(包含 NULL),COUNT(column) 只計算該欄位非 NULL 的 row。

  • 計算不同國家數:COUNT(DISTINCT Country)。
  • 計算每個國家的客戶數:GROUP BY Country 搭配 COUNT。
  • WHERE 在 grouping 前篩 rows;HAVING 在 grouping 後篩 groups。
  • SELECT 中未 aggregate 的 columns 通常必須出現在 GROUP BY。

想找「學生數超過 50 的科系」,篩選條件放在?

4.JOIN 依關聯欄位組合資料

JOIN 是 SQL 最核心的操作之一 — 它把兩個或多個表依照共同的欄位值合併成一個結果集。不同類型的 JOIN 決定了「當某一邊沒有匹配時怎麼辦」。 【INNER JOIN】只輸出兩邊都有匹配的 row。 SELECT S.name, D.dept_name FROM Student S INNER JOIN Department D ON S.dept_id = D.dept_id; 如果某個學生的 dept_id 在 Department 表中不存在,該學生不會出現在結果中。 【LEFT (OUTER) JOIN】左表的所有 row 都保留,右表沒有匹配的部分填 NULL。 SELECT S.name, D.dept_name FROM Student S LEFT JOIN Department D ON S.dept_id = D.dept_id; 即使某個學生的 dept_id 不存在於 Department 表,該學生仍會出現,dept_name 為 NULL。 【RIGHT (OUTER) JOIN】和 LEFT JOIN 相反 — 右表全保留,左表沒匹配的填 NULL。 【FULL (OUTER) JOIN】兩邊都全保留,沒匹配的填 NULL。 【CROSS JOIN】笛卡爾積 — 左表每一 row 和右表每一 row 配對。如果左表 10 row、右表 5 row,結果是 50 row。通常不直接使用,但 WHERE 條件不慎遺漏 JOIN 條件時可能意外產生。 【Self JOIN】一個表和自己 JOIN。例如找出「和 Alice 同系的所有學生」: SELECT S2.name FROM Student S1 JOIN Student S2 ON S1.dept_id = S2.dept_id WHERE S1.name = 'Alice' AND S2.name <> 'Alice'; 【考試連結】(1) 給定 SQL 判斷輸出行數 — 關鍵是理解 INNER 會減少行數,LEFT/RIGHT 保留一邊所有行。(2) 自然連接(NATURAL JOIN)自動用同名欄位 JOIN,但如果有多個同名欄位可能產生非預期結果 — 考古題常用此陷阱。

  • 常見條件是 foreign key 對應 referenced key,例如 Orders.CustomerID = Customers.CustomerID。
  • 缺少或寫錯 join condition 可能產生 Cartesian product 或錯誤配對。
  • Table aliases 可縮短欄位引用並消除同名欄位歧義。
  • 選 INNER 或 OUTER JOIN 取決於未配對 rows 是否仍需保留。

Student 有 5 筆,Department 有 3 筆。其中 1 個學生的 dept_id 不存在於 Department。INNER JOIN vs LEFT JOIN 各輸出幾筆?

一起拆題目

範例 1Customers 有 (Taiwan,Taipei)、(Taiwan,Tainan)、(Japan,Kaohsiung)、(Taiwan,Kaohsiung) 四列。請查出台灣且城市為 Taipei 或 Kaohsiung 的 rows。

  1. 先固定 Country='Taiwan'。
  2. 把兩個城市條件以 OR 組成同一群組。
  3. 用 AND 把 country 條件與城市群組連接。
  4. 逐列代入可得第 1 與第 4 列。

所以答案是:SELECT * FROM Customers WHERE Country='Taiwan' AND (City='Taipei' OR City='Kaohsiung');

範例 2Customers.Country 依序是 Taiwan、Taiwan、Japan、NULL、Japan。求不同非 NULL 國家數,並列出每國 row 數。

  1. COUNT(DISTINCT Country) 忽略 NULL 並去重,得到 Taiwan、Japan。
  2. 不同非 NULL 國家數是 2。
  3. 以 Country GROUP BY 後,Taiwan 有 2、Japan 有 2;NULL 也可能形成一組,依查詢是否先排除 NULL 而定。
  4. 若只要非 NULL groups,可在 grouping 前加 WHERE Country IS NOT NULL。

所以答案是:不同國家數:SELECT COUNT(DISTINCT Country) FROM Customers; 每國數量:SELECT Country, COUNT(*) FROM Customers WHERE Country IS NOT NULL GROUP BY Country;

範例 3Customers(CustomerID, CustomerName) 有 (1,'Mei')、(2,'Bo');Orders(OrderID, CustomerID) 有 (101,1)、(102,1)、(103,3),且 Customers.CustomerID 唯一。請用 INNER JOIN 列出有合法 customer 配對的訂單與姓名。

  1. Customers.CustomerID 是 customer 識別欄位。
  2. Orders.CustomerID 是 join key。
  3. 101、102 的 CustomerID=1,可與 Mei 配對。
  4. 103 的 CustomerID=3 在 Customers 沒有配對,INNER JOIN 不輸出。

所以答案是:SELECT o.OrderID, c.CustomerName FROM Orders AS o INNER JOIN Customers AS c ON o.CustomerID=c.CustomerID; 結果為 (101,'Mei')、(102,'Mei')。

範例 4要找出客戶數至少 2 人的國家,條件應放 WHERE 還是 HAVING?

  1. 先依 Country GROUP BY。
  2. 每組以 COUNT(*) 得到客戶數。
  3. 『至少 2 人』依 aggregate 結果判斷,不是單一 row 屬性。
  4. 因此使用 HAVING COUNT(*) >= 2。

所以答案是:SELECT Country, COUNT(*) FROM Customers GROUP BY Country HAVING COUNT(*) >= 2;

這裡最容易選錯

  • 用 CREATE DATABASE 或不存在的 BUILD TABLE 代替 CREATE TABLE。
  • 混用 AND/OR 卻不加括號,讓 city 條件脫離 country 限制。
  • 把 COUNT(column) 當成一定等於 COUNT(*),忽略 NULL。
  • 用 WHERE 篩選 aggregate 結果;分組後條件應使用 HAVING。
  • SELECT 未 aggregate column 卻沒有放入 GROUP BY。
  • JOIN 遺漏 ON condition,意外產生 Cartesian product。

換你快速判斷

先在心中作答,再展開答案。答不出來時,回頭找本課的對照關係。

1建立 Customers(CustomerID INT, CustomerName VARCHAR(255)) 的基本 SQL 是什麼?

CREATE TABLE Customers (CustomerID INT, CustomerName VARCHAR(255));

CREATE DATABASE 建立 database,不會用這個 column-definition 形式直接建立 table。

2為何混用 AND 與 OR 時應明確加括號?

括號明示需求的 Boolean grouping,避免 OR 條件脫離其他限制,即使知道 AND 通常優先也更安全可讀。

Taiwan 且城市二選一應寫 Country='Taiwan' AND (City='Taipei' OR City='Kaohsiung')。

3COUNT(*)、COUNT(column)、COUNT(DISTINCT column) 有何不同?

COUNT(*) 數 rows;COUNT(column) 數非 NULL values;COUNT(DISTINCT column) 數不同的非 NULL values。

是否忽略 NULL、是否去重,是三者最重要的差異。

4GROUP BY 與 HAVING 分別做什麼?

GROUP BY 依 key 形成 groups;HAVING 依 aggregate 或 group-level 條件篩選形成後的 groups。

Individual-row 條件通常放 WHERE,aggregate 結果條件放 HAVING。

5SQL JOIN 的主要用途是什麼?

依 related columns 組合兩個或更多 tables 的 rows 與 columns。

JOIN 是查詢運算,不等於永久建立 table,也不會自動去除 duplicates。

6INNER JOIN 與 LEFT JOIN 對未配對 rows 的處理有何不同?

INNER JOIN 只保留配對 rows;LEFT JOIN 保留左表全部 rows,右表未配對 columns 以 NULL 表示。

選擇 join type 前,先問是否需要保留左側沒有關聯資料的 records。

最後用考古題驗證

本課連結的題目都已通過可重現的技術覆核,可逐題練習與判分。

開始本課考古題練習

參考來源