SQL进阶随笔--case用法(一)
SQL進階一整個是根據我看了pdf版本的整理以及自己的見解整理。后期也方便我自己查看和復習。
CASE 表達式
CASE 表達式是從 SQL-92 標準開始被引入的??赡芤驗樗窍鄬^新的技術,所以盡管使用起來非常便利,但其真正的價值卻并不怎么為人所知。很多人不用它,或者用它的簡略版函數,例如 DECODE(Oracle)、IF (MySQL)等。然而,正如 Joe Celko 所說,CASE表達式也許是 SQL-92 標準里加入的最有用的特性。如果能用好它,那么 SQL 能解決的問題就會更廣泛,寫法也會更加漂亮。而且,因為 CASE 表達式是不依賴于具體數據庫的技術,所以可以提高 SQL 代碼的可移植性。這里強烈推薦大家改用 CASE 表達式,特別是使用DECODE 函數的 Oracle 用戶 。
正對decode,我們和case進行下對比,然后引出我們的主角case。
DECODE 是 Oracle 用戶很熟悉的函數,它有以下四個不如 CASE 表達式的地方。
? 它是 Oracle 獨有的函數,所以不具有可移植性。
? 分支數最大支持 127 個(參數上限 255 個,一個分支需要 2 個參數)。
? 如果分支數增加,代碼會變得非常難讀。
? 表達能力較弱。具體來說,參數里不能使用謂詞,也不能嵌套子查詢。
ok,現在用一些案例去了解學習下優點眾多的case用法:
#CASE 表達式概述
首先我們來學習一下基本的寫法,CASE 表達式有簡單 CASE 表達式(simple case expression)和搜索 CASE 表達式(searched caseexpression)兩種寫法,它們分別如下所示。
■CASE 表達式的寫法
-- 簡單CASE 表達式 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END -- 搜索CASE 表達式 CASE WHEN sex = '1' THEN '男' WHEN sex = '2' THEN '女' ELSE '其他' END這兩種寫法的執行結果是相同的,“sex”列(字段)如果是 '1' ,那么結果為男;如果是 '2' ,那么結果為女。簡單 CASE 表達式正如其名,寫法簡單,但能實現的事情比較有限。簡單 CASE 表達式能寫的條件,搜索 CASE 表達式也能寫,所以后面采用搜索 CASE 表達式的寫法。
?
我們在編寫 SQL 語句的時候需要注意,在發現為真的 WHEN 子句時,CASE 表達式的真假值判斷就會中止,而剩余的 WHEN 子句會被忽略。為了避免引起不必要的混亂,使用 WHEN 子句時要注意條件的排他性。
■剩余的 WHEN 子句被忽略的寫法示例
-- 例如,這樣寫的話,結果里不會出現“第二” CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END注意事項 1:統一各分支返回的數據類型
雖然這一點無需多言,但這里還是要強調一下:一定要注意 CASE 表達式里各個分支返回的數據類型是否一致。某個分支返回字符型,而其他分支返回數值型的寫法是不正確的。
注意事項 2:不要忘了寫 END
使用 CASE 表達式的時候,最容易出現的語法錯誤是忘記寫 END 。雖然忘記寫時程序會返回比較容易理解的錯誤消息,不算多么致命的錯誤。但是,感覺自己寫得沒問題,而執行時卻出錯的情況大多是由這個原因引起的,所以請一定注意一下。
注意事項 3:養成寫 ELSE 子句的習慣
與 END 不同,ELSE 子句是可選的,不寫也不會出錯。不寫 ELSE 子句時,CASE 表達式的執行結果是 NULL 。但是不寫可能會造成“語法沒有錯誤,結果卻不對”這種不易追查原因的麻煩,所以最好明確地寫上 ELSE 子句(即便是在結果可以為 NULL 的情況下)。養成這樣的習慣后,我們從代碼上就可以清楚地看到這種條件下會生成 NULL,而且將來代碼有修改時也能減少失誤。
#將已有編號方式轉換為新的方式并統計
在進行非定制化統計時,我們經常會遇到將已有編號方式轉換為另外一種便于分析的方式并進行統計的需求。例如,現在有一張按照“‘1:北海道’、‘2:青森’、……、‘47:沖繩’”這種編號方式來統計都道府縣 人口的表,我們需要以東北、關東、九州等地區為單位來分組,并統計人口數量。具體來說,就是統計下表 PopTbl 中的內容,得出如右表“統計結果”所示的結果。
在“統計結果”這張表中,“四國”對應的是表 PopTbl 中的“德島、香川、愛媛、高知 ”,“九 州”對應的是表 PopTbl 中的“福岡、佐賀、長崎”。
大家會怎么實現呢?定義一個包含“地區編號”列的視圖是一種做法,但是這樣一來,需要添加的列的數量將等同于統計對象的編號個數,而且很難動態地修改。
而如果使用 CASE 表達式,則用如下所示的一條 SQL 語句就可以完成。為了便于理解,這里用縣名(pref_name )代替編號作為GROUP BY 的列。
-- 把縣編號轉換成地區編號(1) SELECT CASE pref_name WHEN '德島' THEN '四國' WHEN '香川' THEN '四國' WHEN '愛媛' THEN '四國' WHEN '高知' THEN '四國' WHEN '福岡' THEN '九州' WHEN '佐賀' THEN '九州' WHEN '長崎' THEN '九州' ELSE '其他' END AS district, SUM(population) FROM PopTbl GROUP BY CASE pref_name WHEN '德島' THEN '四國' WHEN '香川' THEN '四國' WHEN '愛媛' THEN '四國' WHEN '高知' THEN '四國' WHEN '福岡' THEN '九州' WHEN '佐賀' THEN '九州' WHEN '長崎' THEN '九州' ELSE '其他' END;這里的關鍵在于將 SELECT 子句里的 CASE 表達式復制到 GROUP BY子句里。需要注意的是,如果對轉換前的列“pref_name ”進行 GROUP BY ,就得不到正確的結果(因為這并不會引起語法錯誤,所以容易被忽視)。
?
同樣地,也可以將數值按照適當的級別進行分類統計。例如,要按人口數量等級(pop_class )查詢都道府縣個數的時候,就可以像下面這樣寫 SQL 語句。
-- 按人口數量等級劃分都道府縣 SELECT CASE WHEN population < 100 THEN '01' WHEN population >= 100 AND population < 200 THEN '02' WHEN population >= 200 AND population < 300 THEN '03' WHEN population >= 300 THEN '04' ELSE NULL END AS pop_class, COUNT(*) AS cnt FROM PopTbl GROUP BY CASE WHEN population < 100 THEN '01' WHEN population >= 100 AND population < 200 THEN '02' WHEN population >= 200 AND population < 300 THEN '03' WHEN population >= 300 THEN '04' ELSE NULL END; pop_class cnt --------- ---- 01 1 02 3 03 3 04 2這個技巧非常好用。不過,必須在 SELECT 子句和 GROUP BY 子句這兩處寫一樣的 CASE 表達式,這有點兒麻煩。后期需要修改的時候,很容易發生只改了這一處而忘掉改另一處的失誤。
所以,如果我們可以像下面這樣寫,那就方便多了。
-- 把縣編號轉換成地區編號(2) :將CASE 表達式歸納到一處 SELECT CASE pref_name WHEN '德島' THEN '四國' WHEN '香川' THEN '四國' WHEN '愛媛' THEN '四國' WHEN '高知' THEN '四國' WHEN '福岡' THEN '九州' WHEN '佐賀' THEN '九州' WHEN '長崎' THEN '九州' ELSE '其他' END AS district, SUM(population) FROM PopTbl GROUP BY district; ←-------GROUP BY 子句里引用了SELECT 子句中定義的別名但是沒錯,這里的 GROUP BY 子句使用的正是 SELECT 子句里定義的列的別稱——district 。但是嚴格來說,這種寫法是違反標準 SQL 的規則的。因為 GROUP BY 子句比 SELECT 語句先執行,所以在 GROUP BY 子句中引用在 SELECT 子句里定義的別稱是不被允許的。事實上,在 Oracle、DB2、SQL Server 等數據庫里采用這種寫法時就會出錯。
不過也有支持這種 SQL 語句的數據庫,例如在 PostgreSQL 和MySQL 中,這個查詢語句就可以順利執行。這是因為,這些數據庫在執行查詢語句時,會先對 SELECT 子句里的列表進行掃描,并對列進行計算。不過因為這是違反標準的寫法,所以這里不強烈推薦大家使用。但是,這樣寫出來的 SQL 語句確實非常簡潔,而且可讀性也很好。
■用一條 SQL 語句進行不同條件的統計
進行不同條件的統計是 CASE 表達式的著名用法之一。例如,我們需要往存儲各縣人口數量的表 PopTbl 里添加上“性別”列,然后求按性別、縣名匯總的人數。具體來說,就是統計表 PopTbl2 中的數據,然后求出如表“統計結果”所示的結果。圖片沒有截取完全。
?
?通常的做法是像下面這樣,通過在 WHERE 子句里分別寫上不同的條件,然后執行兩條 SQL 語句來查詢。
■示例代碼 3
-- 男性人口 SELECT pref_name, SUM(population) FROM PopTbl2 WHERE sex = '1' GROUP BY pref_name; -- 女性人口 SELECT pref_name, SUM(population) FROM PopTbl2 WHERE sex = '2' GROUP BY pref_name;最后需要通過宿主語言或者應用程序將查詢結果按列展開。如果使用UNION ,只用一條 SQL 語句就可以實現,但使用這種做法時,工作量并沒有減少,SQL 語句也會變得很長。而如果使用 CASE 表達式,下面這一條簡單的 SQL 語句就可以搞定。
?
SELECT pref_name, -- 男性人口 SUM( CASE WHEN sex = '1' THEN population ELSE 0 END) AS cnt_m, -- 女性人口 SUM( CASE WHEN sex = '2' THEN population ELSE 0 END) AS cnt_f FROM PopTbl2 GROUP BY pref_name;上面這段代碼所做的是,分別統計每個縣的“男性”(即 '1' )人數和“女性”(即 '2' )人數。也就是說,這里是將“行結構”的數據轉換成了“列結構”的數據。除了 SUM ,COUNT 、AVG 等聚合函數也都可以用于將行結構的數據轉換成列結構的數據。
這個技巧可貴的地方在于,它能將 SQL 的查詢結果轉換為二維表的格式。如果只是簡單地用 GROUP BY 進行聚合,那么查詢后必須通過宿主語言或者 Excel 等應用程序將結果的格式轉換一下,才能使之成為交叉表??瓷厦娴膱绦薪Y果會發現,此時輸出的已經是側欄為縣名、表頭為性別的交叉表了。在制作統計表時,這個功能非常方便。如果用一句話來形容這個技巧,可以這樣說:
?新手用 WHERE 子句進行條件分支,高手用 SELECT 子句進行條件分支。
轉載于:https://www.cnblogs.com/jianshuai520/p/10268320.html
總結
以上是生活随笔為你收集整理的SQL进阶随笔--case用法(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tensorflow tf.layers
- 下一篇: js:封装获取当前元素的所有的哥哥元素节