SQL 中的 CASE 表達式是實現條件邏輯的核心工具,分為「簡單 CASE」與「搜尋 CASE」兩種形式,兩者功能等價,但適用場景略有不同。
適合單一欄位與多個固定值的比對:
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他'
END
支援複雜條件判斷(如範圍、複合條件),彈性更高:
CASE
WHEN sex = '1' THEN '男'
WHEN sex = '2' THEN '女'
ELSE '其他'
END
關鍵差異:簡單 CASE 僅能做等值比較,搜尋 CASE 可使用任意布林表達式(含 IN、BETWEEN、LIKE、IS NULL 等)。
CASE 表達式會依序評估 WHEN 條件,首個符合條件的分支即刻返回,後續分支自動忽略。此特性常被誤用,導致邏輯錯誤:
-- 錯誤示範:永遠無法得到「第二類」
CASE
WHEN col_1 IN ('a', 'b') THEN '第一類'
WHEN col_1 IN ('a') THEN '第二類' -- 永遠不會被執行
ELSE '其他'
END
正確做法是將更嚴格的條件前置,或改用互斥條件。
需求:依國家歸屬洲際,統計人口總數。
SELECT
SUM(population),
CASE country
WHEN '中國' THEN '亞洲'
WHEN '印度' THEN '亞洲'
WHEN '日本' THEN '亞洲'
WHEN '美國' THEN '北美洲'
WHEN '加拿大' THEN '北美洲'
WHEN '墨西哥' THEN '北美洲'
ELSE '其他'
END AS continent
FROM Table_A
GROUP BY
CASE country
WHEN '中國' THEN '亞洲'
WHEN '印度' THEN '亞洲'
WHEN '日本' THEN '亞洲'
WHEN '美國' THEN '北美洲'
WHEN '加拿大' THEN '北美洲'
WHEN '墨西哥' THEN '北美洲'
ELSE '其他'
END;
同樣邏輯可用於薪資分級統計:
SELECT
CASE
WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600 THEN '2'
WHEN salary > 600 AND salary <= 800 THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL
END AS salary_class,
COUNT(*)
FROM Table_A
GROUP BY
CASE
WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600 THEN '2'
WHEN salary > 600 AND salary <= 800 THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL
END;
需求:一張表同時輸出各國男、女性口數(避免 UNION 多次掃表)。
SELECT
country,
SUM(CASE WHEN sex = '1' THEN population ELSE 0 END) AS male_pop,
SUM(CASE WHEN sex = '2' THEN population ELSE 0 END) AS female_pop
FROM Table_A
GROUP BY country;
此技巧將縱向資料轉為橫向報表,極大簡化查詢邏輯。
需求:女員工薪資必須 > 1000,男員工不限。
-- 使用 CASE 的正確寫法
CONSTRAINT check_salary CHECK (
CASE
WHEN sex = '2' THEN
CASE WHEN salary > 1000 THEN 1 ELSE 0 END
ELSE 1
END = 1
)
-- 僅用 CHECK 會導致男員工無法插入
CONSTRAINT check_salary CHECK (sex = '2' AND salary > 1000) -- 錯誤
需求:薪資 ≥ 5000 減 10%,2000–4600 增 15%,其餘不變。若分兩條 UPDATE,中間值會被二次修改。
UPDATE Personnel
SET salary = CASE
WHEN salary >= 5000 THEN salary * 0.9
WHEN salary >= 2000 AND salary < 4600 THEN salary * 1.15
ELSE salary -- 必須保留,否則不符合條件的行會變 NULL
END;
進階應用:交換主鍵值(無需臨時表):
UPDATE SomeTable
SET p_key = CASE
WHEN p_key = 'a' THEN 'b'
WHEN p_key = 'b' THEN 'a'
ELSE p_key
END
WHERE p_key IN ('a', 'b');
利用 IN 或 EXISTS 子查詢,標記匹配狀態:
-- 使用 IN
SELECT keyCol,
CASE WHEN keyCol IN (SELECT keyCol FROM tbl_B)
THEN 'Matched' ELSE 'Unmatched' END AS Label
FROM tbl_A;
-- 使用 EXISTS(通常效能較佳)
SELECT keyCol,
CASE WHEN EXISTS (
SELECT * FROM tbl_B WHERE tbl_A.keyCol = tbl_B.keyCol
) THEN 'Matched' ELSE 'Unmatched' END AS Label
FROM tbl_A;
需求:單門課學生回傳該課程 ID,多門課學生回傳主修課程 ID。
SELECT std_id,
CASE
WHEN COUNT(*) = 1 THEN MAX(class_id)
ELSE MAX(CASE WHEN main_class_flg = 'Y' THEN class_id ELSE NULL END)
END AS main_class
FROM Studentclass
GROUP BY std_id;
此處巧妙結合 COUNT、MAX 與巢狀 CASE,單一查詢解決雙重邏輯。
CASE col_1
WHEN 1 THEN 'Right'
WHEN NULL THEN 'Wrong' -- 永遠不會執行!
END
WHEN NULL 等同於 WHEN col_1 = NULL,結果永遠為 UNKNOWN。正確寫法:
CASE
WHEN col_1 = 1 THEN 'Right'
WHEN col_1 IS NULL THEN 'Wrong'
END
CASE 表達式是 SQL 中最靈活的條件邏輯工具,掌握其順序評估、NULL 語義與聚合函數結合技巧,能將複雜業務邏輯封裝在單一聲明式查詢中,提升可維護性與效能。