CodeGym /課程 /SQL SELF /條件運算式:CASE WHEN ... THEN ... ELSE ... END

條件運算式:CASE WHEN ... THEN ... ELSE ... END

SQL SELF
等級 10 , 課堂 0
開放

你大概早就碰過程式語言裡的條件運算式了吧:if-elseswitch-case 這些東西。在 SQL 裡也有自己的條件工具:就是 CASE。它讓你可以直接在查詢裡做決策:如果條件成立,做這個,不成立就做別的。

CASE 這招特別好用,尤其是你要處理可能有 NULL 值的資料時。語法超簡單,像小抄一樣,來看看:

CASE
    WHEN 條件1 THEN 結果1
    WHEN 條件2 THEN 結果2
    ...
    ELSE 預設結果
END

是不是很直覺?「如果這樣,就做這個,不然就做那個」。超好記:「WHEN 就是如果,THEN 就是要做什麼,ELSE 就是都不符合時要做什麼」。

範例:商品分類

想像一下,我們有個 products 表,裡面有個 price 欄位,我們想根據價格把商品分組。

id name price
1 Magic Wand 120
2 Potion Set 45
3 Crystal Ball 75
4 Enchanted Map NULL
5 Broomstick 99
6 Spell Book 180
SELECT
    name AS product_name,
    price,
    CASE
        WHEN price IS NULL THEN '未知'
        WHEN price < 50 THEN '平價'
        WHEN price BETWEEN 50 AND 100 THEN '標準'
        ELSE '高級'
    END AS price_category
FROM products;

這裡發生了什麼?

  1. 如果商品的 price 沒填(NULL),我們顯示分類為 '未知'
  2. 如果價格小於 50,這商品就算「平價」'平價'
  3. 如果價格在 50 到 100 之間,就是 '標準'
  4. 其他全部都是高級貨 '高級'

結果長這樣:

product_name price price_category
Magic Wand 120 高級
Potion Set 45 平價
Crystal Ball 75 標準
Enchanted Map NULL 未知
Broomstick 99 標準
Spell Book 180 高級

SQL 就像魔法師一樣,讀每一行 products,然後幫你聰明地分類。

CASE WHEN 處理 NULL

資料裡常常會有漏掉的值(哈囉 NULL),這時你就要補點東西進去。比如我們有個 users 表,裡面有 email 欄位,對於沒填 email 的用戶,我們想顯示 '未填寫'

user_id name email
1 Alex Lin alex@example.com
2 Maria Chi NULL
3 Anna Song anna@magic.com
4 Otto Art NULL
5 John Smith john@wizard.org
SELECT
    user_id,
    name,
    CASE
        WHEN email IS NULL THEN '未填寫'
        ELSE email
    END AS email_address
FROM users;
user_id name email_address
1 Alex Lin alex@example.com
2 Maria Chi 未填寫
3 Anna Song anna@magic.com
4 Otto Art 未填寫
5 John Smith john@wizard.org

SQL 在這裡就像薩滿一樣,讓半空的欄位活過來。如果 email 沒填,就補上 '未填寫',有填就直接顯示。

數字的條件運算式

有時候你不只是要補值,還要做點新邏輯。比如我們有個 students 表,裡面有 score(分數)和 name 欄位。

name score
Alex Lin 95
Maria Chi 82
Anna Song 48
Otto Art NULL
John Smith 67
Zoe Black 30

我們想根據分數把學生分成「優秀」、「及格」和「不及格」。

SELECT
    name AS student_name,
    score,
    CASE
        WHEN score IS NULL THEN '無分數'
        WHEN score >= 90 THEN '優秀'
        WHEN score >= 50 THEN '及格'
        ELSE '不及格'
    END AS performance_category
FROM students;
student_name score performance_category
Alex Lin 95 優秀
Maria Chi 82 及格
Anna Song 48 不及格
Otto Art NULL 無分數
John Smith 67 及格
Zoe Black 30 不及格

SQL 很貼心地幫學生分級,像嚴格的考官:90 分以上才「優秀」,50 分以上「及格」。分數不夠...你懂的。

分組與 NULL 處理

處理資料分組也是 CASE WHEN 超強的地方。想像我們有個 orders 表,要算每個狀態的訂單數,包括狀態是 NULL 的訂單。

order_id status
1 Completed
2 Pending
3 NULL
4 Shipped
5 Completed
6 NULL
7 Pending
8 Completed
9 Shipped
10 NULL
SELECT
    CASE
        WHEN status IS NULL THEN '無狀態'
        ELSE status
    END AS order_status,
    COUNT(*)
FROM orders
GROUP BY 
    CASE
        WHEN status IS NULL THEN '無狀態'
        ELSE status
    END;

這個查詢會把 NULL 狀態補成 '無狀態',然後算每組訂單數。結果如下:

order_status count
Completed 3
Pending 2
Shipped 2
無狀態 3

實戰案例:「魔術」CASE WHEN

範例 1:排序時考慮 NULL

有時候你想讓 NULL 值在排序時出現在最前或最後。像是任務清單,重要的任務要排前面,沒設定優先級(NULL)的就丟最後。

task_id task_name priority
1 Fix bugs 1
2 Update documentation 3
3 Plan sprint NULL
4 Code review 2
5 Organize meeting NULL
6 Deploy release 1
SELECT
    task_name,
    priority,
    CASE
        WHEN priority IS NULL THEN 1
        ELSE 0
    END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;

這裡我們加了一個「虛擬」欄位 priority_sort,讓 NULL 都排在後面,其他照順序排。

task_name priority priority_sort
Deploy release 1 0
Fix bugs 1 0
Code review 2 0
Update documentation 3 0
Plan sprint NULL 1
Organize meeting NULL 1

範例 2:計算時考慮 NULL

再來想像一下,我們要算訂單總金額,orders 表裡 discount(折扣)欄位有時是 NULL,代表沒折扣。

order_id total_price discount
101 100 10
102 200 NULL
103 150 15
104 120 NULL
105 80 5

我們要把 NULL 換成 0,這樣計算才不會壞掉。

SELECT 
    order_id,
    total_price,
    discount,
    total_price - 
    CASE
        WHEN discount IS NULL THEN 0
        ELSE discount
    END AS final_price
FROM orders;
order_id total_price discount final_price
101 100 10 90
102 200 NULL 200
103 150 15 135
104 120 NULL 120
105 80 5 75

這個 CASE 魔法讓你不用怕 NULL 讓數學爆炸。

對於 orderid = 101: discount = 10. finalprice = 100 - 10 = 90。對於 orderid = 102: discount = NULL. CASE 回傳 0. finalprice = 200 - 0 = 200。對於 orderid = 103: discount = 15. finalprice = 150 - 15 = 135。對於 orderid = 104: discount = NULL. CASE 回傳 0. finalprice = 120 - 0 = 120。對於 orderid = 105: discount = 5. finalprice = 80 - 5 = 75。

範例 3:顯示用戶狀態

日常工作常常要顯示用戶狀態(像「啟用中」或「等待中」),或是提醒沒資料。比如 users 表有 last_login 欄位,記錄最後登入日期。

user_id name last_login
1 Alex Lin 2024-12-10
2 Maria Chi 2025-04-20
3 Anna Song NULL
4 Otto Art 2025-05-01
5 Liam Park 2025-05-25
SELECT
    user_id,
    name,
    CASE
        WHEN last_login IS NULL THEN '從未登入'
        WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN '不活躍'
        ELSE '啟用中'
    END AS user_status
FROM users;

這個查詢讓管理系統活起來:沒登入過的叫「從未登入」,很久沒來的算「不活躍」,其他就是「啟用中」!

user_id name user_status
1 Alex Lin 不活躍
2 Maria Chi 不活躍
3 Anna Song 從未登入
4 Otto Art 不活躍
5 Liam Park 啟用中

常見錯誤與避免方法

漏掉 ELSE 如果你沒寫 ELSE,SQL 只要沒符合條件就會回傳 NULL。這通常不是你想要的,所以最好都明確寫 ELSE,就算你覺得所有情況都包了。

CASE
    WHEN condition THEN result
    -- ELSE '預設值' -- 別忘了!
END

複雜條件沒加括號: 如果你有很多 ANDORNOT,一定要加括號。不然 SQL 會「想歪」喔。

CASE
    WHEN (column1 IS NOT NULL AND column2 > 5) THEN '有效'
    ELSE '無效'
END

處理 NULL 記得 NULL 永遠不等於(=)任何東西。舉例:

CASE
    WHEN column = NULL THEN '錯誤!' -- 錯誤寫法!
    WHEN column IS NULL THEN '正確!' -- 這才對。
END
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION