首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL CASE WHEN 多場景實戰:從基礎語法到複雜業務邏輯建模

     編輯:MySQL 資料庫相關知識

CASE WHEN 是 MySQL 流程控制函數的核心,支援簡單/搜索/嵌套三種形式,廣泛用於報表轉換、分桶統計、動態排序等場景。本文通過建表、插數、多維案例,系統講解三大用法及實戰技巧。

環境準備

CREATE TABLE `lee` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` char(20) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO lee(name,birthday) VALUES ('sam','1990-01-01');
INSERT INTO lee(name,birthday) VALUES ('lee','1980-01-01');
INSERT INTO lee(name,birthday) VALUES ('john','1985-01-01');

用法一:搜索型 CASE(條件表達式)

SELECT name,
       CASE
         WHEN birthday < '1981' THEN 'old'
         WHEN birthday > '1988' THEN 'young'
         ELSE 'ok'
       END AS age_group
FROM lee;

結果:lee→old、john→ok、sam→young。

注意:日期字面量建議加引號 '1981',或使用 YEAR(birthday) 避免隱式轉換歧義。

用法二:簡單型 CASE(值比較)

SELECT name,
       CASE name
         WHEN 'sam'  THEN 'young'
         WHEN 'lee'  THEN 'handsome'
         ELSE 'good'
       END AS label
FROM lee;

等同於 CASE WHEN name='sam' THEN ...,但可讀性更高,適用於枚舉值映射。

用法三:混合嵌套與多列條件

SELECT name, birthday,
       CASE
         WHEN birthday > '1983' THEN 'young'
         WHEN name = 'lee' THEN 'handsome'
         ELSE 'just so so'
       END AS complex_label
FROM lee;

實戰案例:罰款分級統計

CREATE TABLE penalties (
  paymentno INT PRIMARY KEY,
  payment_date DATE NOT NULL,
  amount DECIMAL(7,2) NOT NULL
);
INSERT INTO penalties VALUES (1,'2008-01-01',3.45),(2,'2009-01-01',50.45),(3,'2008-07-01',80.45);

-- 分級標籤
SELECT payment_date, amount,
       CASE
         WHEN amount >= 0 AND amount < 40 THEN 'low'
         WHEN amount >= 40 AND amount < 80 THEN 'moderate'
         WHEN amount >= 80 THEN 'high'
         ELSE 'null'
       END AS level
FROM penalties;

-- 子查詢篩選 low 級別
SELECT * FROM (
  SELECT paymentno, amount,
         CASE
           WHEN amount >= 0 AND amount < 40 THEN 'low'
           WHEN amount >= 40 AND amount < 80 THEN 'moderate'
           WHEN amount >= 80 THEN 'high'
           ELSE 'incorrect'
         END AS lvl
  FROM penalties
) p WHERE p.lvl = 'low';

複雜業務場景:設備使用狀態判定

SELECT DISTINCT a.PatientID, a.PatientCode, a.PatientSex, a.MobileNo, a.HomePhoneNo,
       a.UserAge, a.PatientName, a.PatientIDCard,
       DATE_FORMAT(a.RegistDate,'%Y-%m-%d') AS RegistDate,
       CASE
         WHEN b.usedstartTime IS NOT NULL AND b.UsedEndTime IS NULL THEN '1'  -- 使用中
         WHEN b.usedstartTime IS NOT NULL AND b.UsedEndTime IS NOT NULL THEN '2' -- 已歸還
       END AS usedState
FROM mets_v_patient_baseinfo a
LEFT JOIN mets_devices_used_history b ON a.patientid = b.PatientID
WHERE (SELECT IFNULL(IsDeleted,0) FROM userpublic_info WHERE UserID = a.PatientID) = 0
ORDER BY PatientID DESC LIMIT 0,15;

最佳實踐提示

  1. 類型一致:THEN 後表達式類型必須兼容,否則隱式轉換導致精度損失或報錯。
  2. 短路求值:條件順序影響性能,高選擇性條件前置。
  3. NULL 處理:WHEN col = NULL 永不匹配,需用 IS NULL。
  4. 可讀性:超過 5 分支建議拆視圖或應用層處理,SQL 保持單一職責。
  5. 索引友好:CASE 列不可直接用於索引查找,若頻繁篩選結果值,考慮物化列+索引。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved