case when的判断顺序_CASE 表达式
一、語法及作用
使用CASE表達式可以幫助我們解決復(fù)雜的查詢問題,相當(dāng)于條件判斷的函數(shù),判斷每一行是不是滿足條件。
CASE WHEN (判斷表達式) THEN (表達式)WHEN (判斷表達式) THEN (表達式)WHEN (判斷表達式) THEN (表達式)....ELSE(表達式) END;CASE 表達式會從對最初的WHEN子句中的“< 求值表達式 >”進行求值開始執(zhí)行。所謂求值,就是要調(diào)查該表達式的真值是什么。如果結(jié)果為真(TRUE),那么就返回THEN子句中的表達式,CASE表達式的執(zhí)行到此為止。如果結(jié)果不為真,那么就跳轉(zhuǎn)到下一條WHEN子句的求值之中。 如果直到最后的WHEN子句為止返回結(jié)果都不為真,那么就會返回ELSE中的表達式,執(zhí)行終止。
二、注意事項
- 在發(fā)現(xiàn)為真的 WHEN 子句時, CASE 表達式的真假值判斷就會中止,而剩余的 WHEN 子句會被忽略。因此,為了避免引起不必要的混亂,使用 WHEN 子句時要注意條件的排他性。
- CASE 表達式里各個分支返回的數(shù)據(jù)類型必須一致,如果不一致,則需使用CAST()函數(shù)轉(zhuǎn)換數(shù)據(jù)類型。
- 雖然CASE表達式中的ELSE子句可以省略,但為了讓SQL語句更加容易理解,還是盡量不要省略。
- CASE 表達式中的 END 不能省略。
- 使用CASE表達式能夠?qū)ELECT語句的結(jié)果進行組合。
三、適用情況
3.1 將已有編號方式轉(zhuǎn)換為新的方式并統(tǒng)計
例如,統(tǒng)計下表 PopTbl 中的內(nèi)容,得出如右表“統(tǒng)計結(jié)果”所示的結(jié)果。
首先,可以通過定義一個包含“地區(qū)編號”列的視圖來實現(xiàn)。但是這種方法需要添加的行的數(shù)量將等同于統(tǒng)計對象的編號個數(shù),而且很難動態(tài)地修改。因此,可以使用CASE表達式來實現(xiàn):
SELECT CASE WHEN pref_name IN ('德島', '香川', '愛媛', '高知') THEN '四國'WHEN pref_name IN ('福岡', '佐賀', '長崎') THEN '九州'ELSE '其他'END AS district,SUM(population) AS population FROM PopTbl GROUP BY CASE WHEN pref_name IN ('德島', '香川', '愛媛', '高知') THEN '四國'WHEN pref_name IN ('福岡', '佐賀', '長崎') THEN '九州'ELSE '其他'END ORDER BY population DESC;這里的關(guān)鍵在于將SELECT子句里的CASE表達式復(fù)制到 GROUP BY 子句里。后期修改時有可能只改了一處而忘了另一處。因此,可以在 GROUP BY 子句中引用 SELECT 子句中定義的別名 (如下代碼所示),這樣寫出來的 SQL 語句確實非常簡潔,而且可讀性也很好 。
SELECT CASE WHEN pref_name IN ('德島', '香川', '愛媛', '高知') THEN '四國'WHEN pref_name IN ('福岡', '佐賀', '長崎') THEN '九州'ELSE '其他'END AS district,SUM(population) AS population FROM PopTbl GROUP BY district ORDER BY population DESC;嚴格來說,這種寫法是違反標(biāo)準(zhǔn) SQL 的規(guī)則的,因為 GROUP BY 子句比 SELECT 語句先執(zhí)行。事實上,在 Oracle、DB2、 SQL Server 等數(shù)據(jù)庫里采用這種寫法時就會出錯。 不過在 PostgreSQL 和 MySQL 中,這個查詢語句就可以順利執(zhí)行。這是因為,這些數(shù)據(jù)庫在執(zhí)行查詢語句時,會先對 SELECT 子句里的列表進行掃描,并對列進行計算。不過因為這是違反標(biāo)準(zhǔn)的寫法,所以這里不強烈推薦大家使用。
3.2 行列轉(zhuǎn)換:在聚合函數(shù)中使用CASE WHEN 表達式
3.2.1 統(tǒng)計下表 PopTbl2 中的內(nèi)容,得出如右表“統(tǒng)計結(jié)果”所示的結(jié)果。
SELECT pref_name,SUM(CASE WHEN sex = 1 THEN population ELSE 0 END) AS '男性人口',SUM(CASE WHEN sex = 0 THEN population ELSE 0 END) AS '女性人口' FROM PopTbl2 GROUP BY pref_name;3.2.2 統(tǒng)計 PopTbl2 表中的容,得出如下表所示的結(jié)果。
SELECT CASE WHEN sex = 1 THEN 'male' ELSE 'female' END AS sex2, SUM(population) AS 'total', SUM(CASE WHEN pref_name = '德島' THEN population ELSE 0 END) AS '德島', SUM(CASE WHEN pref_name = '香川' THEN population ELSE 0 END) AS '香川', SUM(CASE WHEN pref_name = '愛媛' THEN population ELSE 0 END) AS '愛媛', SUM(CASE WHEN pref_name = '高知' THEN population ELSE 0 END) AS '高知', SUM(CASE WHEN pref_name IN ('德島', '香川', '愛媛', '高知') THEN population ELSE 0 END) AS '四國' FROM PopTbl2 GROUP BY sex2;3.3 表之間的數(shù)據(jù)匹配:在 CASE WHEN 表達式中使用子查詢
方法一:子查詢 (X 和 O 表示)
SELECT course_name,CASE WHEN course_id IN (SELECT course_id FROM OpenCourses WHERE month = '200706')THEN 'O' ELSE 'X' END AS 'June',CASE WHEN course_id IN (SELECT course_id FROM OpenCourses WHERE month = '200707')THEN 'O' ELSE 'X' END AS 'July',CASE WHEN course_id IN (SELECT course_id FROM OpenCourses WHERE month = '200708')THEN 'O' ELSE 'X' END AS 'August' FROM CourseMaster;方法二:聯(lián)結(jié) (0 和 1表示)
SELECT a.course_name,MAX(CASE WHEN b.month = '200706' THEN 1 ELSE 0 END) AS 'June',MAX(CASE WHEN b.month = '200707' THEN 1 ELSE 0 END) AS 'July',MAX(CASE WHEN b.month = '200708' THEN 1 ELSE 0 END) AS 'August' FROM CourseMaster AS a LEFT JOIN OpenCourses AS b ON a.course_id = b.course_id GROUP BY a.course_name;3.4 在 CASE 表達式中使用聚合函數(shù)
如表 StudentClub 所示,這張表的主鍵是“學(xué)號、社團 ID”,存儲了學(xué)生和社團之間多對多的關(guān)系。有的學(xué)生同時加入了多個社團(如學(xué)號為 100、200 的學(xué)生),有的學(xué)生只加入了某一個社團(如學(xué)號為 300、400、500 的學(xué)生)。對于加入了多個社團的學(xué)生,我們通過將其“主社團標(biāo)志”列設(shè)置為 Y 或者 N 來表明哪一個社團是他的主社團;對于只加入了一個社團的學(xué)生,我們將其“主社團標(biāo)志”列設(shè)置為 N。
接下來,我們需要查詢獲取只加入了一個社團的學(xué)生的社團 ID 以及獲取加入了多個社團的學(xué)生的主社團 ID,并將結(jié)果存放在一個表中。
方法一:UNION ALL
SELECT std_id, MAX(club_id) AS 'main_club' FROM StudentClub GROUP BY std_id HAVING COUNT(club_id) = 1 UNION ALL SELECT std_id, club_id AS 'main_club' FROM StudentClub WHERE main_club_flg = 'Y' ORDER BY std_id;方法二:CASE WHEN 表達式
SELECT std_id, CASE WHEN COUNT(club_id) = 1 THEN MAX(club_id)ELSE MAX(CASE WHEN main_club_flg = 'Y' THEN club_id ELSE NULL END) END AS 'main_club' FROM StudentClub GROUP BY std_id;3.5 多列數(shù)據(jù)的最大值
針對每一個key_col,取出x、y、z中最大的值 (取出每一行的最大值)
方法一:自己想的
SELECT key_col,CASE WHEN x > y AND x > z THEN xWHEN y > x AND y > z THEN yELSE zEND AS 'max_col' FROM Greatests;方法二:窮盡討論
SELECT key_col,CASE WHEN CASE WHEN x < y THEN x ELSE y END < z THEN z ELSECASE WHEN x < y THEN y ELSE x ENDEND AS greatest FROM Greatests;方法三:運用 UNION ALL 進行行列轉(zhuǎn)換
SELECT key_col, MAX(col) AS greatest FROM(SELECT key_col, x AS col FROM GreatestsUNION ALLSELECT key_col, y AS col FROM GreatestsUNION ALLSELECT key_col, z AS col FROM Greatests) AS a GROUP BY key_col;方法四:GREATEST() 函數(shù)
SELECT key_col, GREATEST(x, y, z) AS greatest FROM Greatests;GREATEST() 函數(shù)介紹:
https://www.w3schools.com/sql/func_mysql_greatest.asp?www.w3schools.com3.6 在 ORDER BY 語句中使用 CASE WHEN 表達式
3.6.1 針對3.5中的結(jié)果,將結(jié)果按照 B-A-D-C的順序排序
SELECT key_col,CASE WHEN CASE WHEN x < y THEN x ELSE y END < z THEN z ELSECASE WHEN x < y THEN y ELSE x ENDEND AS greatest FROM Greatests ORDER BY (CASE WHEN key_col = 'B' THEN 1WHEN key_col = 'A' THEN 2WHEN key_col = 'D' THEN 3ELSE 4 END);3.6.2 如果job是"SALESMAN",則根據(jù)"comm"排序,否則根據(jù)"sal"排序
方法1:
SELECT ename, sal, job, comm FROM emp ORDER BY CASE WHEN job = 'SALESMAN' THEN commELSE salEND;方法2:
SELECT ename, sal, job, comm,CASE WHEN job = 'SALESMAN' THEN commELSE salEND AS ordered FROM emp ORDER BY 5;3.7 使用 CASE WHEN 語句在 UPDATE 語句里進行條件分支:
例如:對公司工資表中(Salaries)的員工工資(salary)進行更新:對當(dāng)前工資為 30 萬日元以上的員工,降薪 10%;對當(dāng)前工資為 25 萬日元以上且不滿 28 萬日元的員工,加薪 20%。
UPDATE SalariesSET salary = CASE WHEN salary > 300000 THEN salary * 0.9WHEN salary >250000 AND salary <280000 THEN salary * 1.2ELSE salaryEND;3.8 調(diào)換主鍵值:
通常,當(dāng)我們想調(diào)換主鍵值 a 和 b 時,需要將主鍵值臨時轉(zhuǎn)換成某個中間值。使用這種方法時需要執(zhí)行 3 次 UPDATE 操作:
-- 1. 將 a 轉(zhuǎn)換為中間值 d UPDATE SomeTable SET p_key = 'd' WHERE p_key = 'a';-- 2.將b調(diào)換為a UPDATE SomeTable SET p_key = 'a' WHERE p_key = 'b';-- 3.將d調(diào)換為b UPDATE SomeTable SET p_key = 'b' WHERE p_key = 'd';但是,如果使用 CASE 表達式,1 次就可以做到:
UPDATE SomeTable SET p_key = CASE WHEN p_key = 'a' THEN 'b'WHEN p_key = 'b' THEN 'a'ELSE p_keyEND;一般來說需要進行這樣的調(diào)換大多是因為表的設(shè)計出現(xiàn)了問題,所以請先重新審視一下表的設(shè)計,去掉不必要的約束。
四、練習(xí)
表關(guān)系請參考如下文章 (SQL面試50題) 中的四張表
shanshant:SQL面試50題?zhuanlan.zhihu.com練習(xí)一:查詢每門課程的及格人數(shù)和不及格人數(shù)
方法一:自己寫的
SELECT c_id, SUM(及格) AS 及格人數(shù), SUM(不及格) AS 不及格人數(shù) FROM (SELECT c_id,CASE WHEN score >=60 THEN 1 ELSE 0 END AS '及格',CASE WHEN score <60 THEN 1 ELSE 0 END AS '不及格'FROM scores) AS c GROUP BY c_id;方法二:參考猴子老師的
SELECT c_id, SUM(CASE WHEN score >= 60 THEN 1ELSE 0END) AS 及格人數(shù), SUM(CASE WHEN score < 60 THEN 1ELSE 0END) AS 不及格人數(shù) FROM scores GROUP BY c_id;練習(xí)二:使用分段 [100-85], [85-70], [70-60], [<60]來統(tǒng)計各科成績,分別統(tǒng)計:各分數(shù)段人數(shù),課程號和課程名稱。
SELECT a.c_id, b.c_name, SUM(CASE WHEN score >= 85 THEN 1ELSE 0END) AS 85至100分數(shù)段, SUM(CASE WHEN score >= 70 AND score < 85 THEN 1ELSE 0END) AS 70至85分數(shù)段, SUM(CASE WHEN score >= 60 AND score < 70 THEN 1ELSE 0END) AS 60至70分數(shù)段, SUM(CASE WHEN score < 60 THEN 1ELSE 0END) AS 不及格 FROM scores AS a RIGHT JOIN classes AS b ON a.c_id = b.id GROUP BY a.c_id, b.c_name;總結(jié)
以上是生活随笔為你收集整理的case when的判断顺序_CASE 表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 看本地网速_安装 ANSYS 本地帮助
- 下一篇: 哨兵机器人钢力士_哨兵胳膊都被卸了?巴西