這篇文章主要介紹了SQL中CASE表達(dá)式怎么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)長(zhǎng)期為上1000家客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏(yíng)平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為市中企業(yè)提供專(zhuān)業(yè)的成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè),市中網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
首先我們來(lái)學(xué)習(xí)一下基本的寫(xiě)法,CASE 表達(dá)式有簡(jiǎn)單 CASE 表達(dá)式
(simple case expression)和搜索 CASE 表達(dá)式(searched case
expression)兩種寫(xiě)法,它們分別如下所示。
這兩種寫(xiě)法的執(zhí)行結(jié)果是相同的,“sex”列(字段)如果是 '1' ,那
么結(jié)果為男;如果是 '2' ,那么結(jié)果為女。簡(jiǎn)單 CASE 表達(dá)式正如其
名,寫(xiě)法簡(jiǎn)單,但能實(shí)現(xiàn)的事情比較有限。
我們?cè)诰帉?xiě) SQL 語(yǔ)句的時(shí)候需要注意,在發(fā)現(xiàn)為真的 WHEN 子句
時(shí),CASE 表達(dá)式的真假值判斷就會(huì)中止,而剩余的 WHEN 子句會(huì)被
忽略。為了避免引起不必要的混亂,使用 WHEN 子句時(shí)要注意條件的
排他性.
此外,使用 CASE 表達(dá)式的時(shí)候,還需要注意以下幾點(diǎn)。
注意事項(xiàng) 1:統(tǒng)一各分支返回的數(shù)據(jù)類(lèi)型
雖然這一點(diǎn)無(wú)需多言,但這里還是要強(qiáng)調(diào)一下:一定要注意 CASE 表
達(dá)式里各個(gè)分支返回的數(shù)據(jù)類(lèi)型是否一致。某個(gè)分支返回字符型,而
其他分支返回?cái)?shù)值型的寫(xiě)法是不正確的。
注意事項(xiàng) 2:不要忘了寫(xiě) END
使用 CASE 表達(dá)式的時(shí)候,最容易出現(xiàn)的語(yǔ)法錯(cuò)誤是忘記寫(xiě) END 。雖
然忘記寫(xiě)時(shí)程序會(huì)返回比較容易理解的錯(cuò)誤消息,不算多么致命的錯(cuò)
誤。但是,感覺(jué)自己寫(xiě)得沒(méi)問(wèn)題,而執(zhí)行時(shí)卻出錯(cuò)的情況大多是由這
個(gè)原因引起的,所以請(qǐng)一定注意一下。
注意事項(xiàng) 3:養(yǎng)成寫(xiě) ELSE 子句的習(xí)慣
與 END 不同,ELSE 子句是可選的,不寫(xiě)也不會(huì)出錯(cuò)。不寫(xiě) ELSE 子
句時(shí),CASE 表達(dá)式的執(zhí)行結(jié)果是 NULL 。但是不寫(xiě)可能會(huì)造成“語(yǔ)法
沒(méi)有錯(cuò)誤,結(jié)果卻不對(duì)”這種不易追查原因的麻煩,所以最好明確地
寫(xiě)上 ELSE 子句(即便是在結(jié)果可以為 NULL 的情況下)。養(yǎng)成這樣
的習(xí)慣后,我們從代碼上就可以清楚地看到這種條件下會(huì)生成 NULL
,而且將來(lái)代碼有修改時(shí)也能減少失誤。
將已有編號(hào)方式轉(zhuǎn)換為新的方式并統(tǒng)計(jì)
在進(jìn)行非定制化統(tǒng)計(jì)時(shí),我們經(jīng)常會(huì)遇到將已有編號(hào)方式轉(zhuǎn)換為另外
一種便于分析的方式并進(jìn)行統(tǒng)計(jì)的需求。
例如,現(xiàn)在有一張按照“‘1:北海道’、‘2:青森’、……、‘47:沖
繩’”這種編號(hào)方式來(lái)統(tǒng)計(jì)都道府縣 人口的表,我們需要以東北、關(guān)
東、九州等地區(qū)為單位來(lái)分組,并統(tǒng)計(jì)人口數(shù)量。具體來(lái)說(shuō),就是統(tǒng)
計(jì)下表 PopTbl 中的內(nèi)容,得出如上表“統(tǒng)計(jì)結(jié)果”所示的結(jié)果。
這里的關(guān)鍵在于將 SELECT 子句里的 CASE 表達(dá)式復(fù)制到 GROUP BY
子句里。需要注意的是,如果對(duì)轉(zhuǎn)換前的列“pref_name ”進(jìn)行 GROUP
BY ,就得不到正確的結(jié)果(因?yàn)檫@并不會(huì)引起語(yǔ)法錯(cuò)誤,所以容易
被忽視)。
同樣地,也可以將數(shù)值按照適當(dāng)?shù)募?jí)別進(jìn)行分類(lèi)統(tǒng)計(jì)。例如,要按人
口數(shù)量等級(jí)(pop_class )查詢(xún)都道府縣個(gè)數(shù)的時(shí)候,就可以像下
面這樣寫(xiě) SQL 語(yǔ)句。
這個(gè)技巧非常好用。不過(guò),必須在 SELECT 子句和 GROUP BY 子句這
兩處寫(xiě)一樣的 CASE 表達(dá)式,這有點(diǎn)兒麻煩。后期需要修改的時(shí)候,
很容易發(fā)生只改了這一處而忘掉改另一處的失誤。
所以,如果我們可以像下面這樣寫(xiě),那就方便多了。
沒(méi)錯(cuò),這里的 GROUP BY 子句使用的正是 SELECT 子句里定義的列的
別稱(chēng)——district 。但是嚴(yán)格來(lái)說(shuō),這種寫(xiě)法是違反標(biāo)準(zhǔn) SQL 的規(guī)
則的。因?yàn)?GROUP BY 子句比 SELECT 語(yǔ)句先執(zhí)行,所以在 GROUP
BY 子句中引用在 SELECT 子句里定義的別稱(chēng)是不被允許的。事實(shí)
上,在 Oracle、DB2、SQL Server 等數(shù)據(jù)庫(kù)里采用這種寫(xiě)法時(shí)就會(huì)出
錯(cuò)。
不過(guò)也有支持這種 SQL 語(yǔ)句的數(shù)據(jù)庫(kù),例如在 PostgreSQL 和
MySQL 中,這個(gè)查詢(xún)語(yǔ)句就可以順利執(zhí)行。這是因?yàn)?,這些數(shù)據(jù)庫(kù)
在執(zhí)行查詢(xún)語(yǔ)句時(shí),會(huì)先對(duì) SELECT 子句里的列表進(jìn)行掃描,并對(duì)列
進(jìn)行計(jì)算。不過(guò)因?yàn)檫@是違反標(biāo)準(zhǔn)的寫(xiě)法,所以這里不強(qiáng)烈推薦大家
使用。但是,這樣寫(xiě)出來(lái)的 SQL 語(yǔ)句確實(shí)非常簡(jiǎn)潔,而且可讀性也
很好。
用一條 SQL 語(yǔ)句進(jìn)行不同條件的統(tǒng)計(jì)
進(jìn)行不同條件的統(tǒng)計(jì)是 CASE 表達(dá)式的著名用法之一。例如,我們需
要往存儲(chǔ)各縣人口數(shù)量的表 PopTbl 里添加上“性別”列,然后求按性
別、縣名匯總的人數(shù)。具體來(lái)說(shuō),就是統(tǒng)計(jì)表 PopTbl2 中的數(shù)據(jù),然
后求出如表“統(tǒng)計(jì)結(jié)果”所示的結(jié)果。
上面這段代碼所做的是,分別統(tǒng)計(jì)每個(gè)縣的“男性”(即 '1' )人數(shù)
和“女性”(即 '2' )人數(shù)。也就是說(shuō),這里是將“行結(jié)構(gòu)”的數(shù)據(jù)轉(zhuǎn)換
成了“列結(jié)構(gòu)”的數(shù)據(jù)。除了 SUM ,COUNT 、AVG 等聚合函數(shù)也都可以
用于將行結(jié)構(gòu)的數(shù)據(jù)轉(zhuǎn)換成列結(jié)構(gòu)的數(shù)據(jù)。
這個(gè)技巧可貴的地方在于,它能將 SQL 的查詢(xún)結(jié)果轉(zhuǎn)換為二維表的
格式。如果只是簡(jiǎn)單地用 GROUP BY 進(jìn)行聚合,那么查詢(xún)后必須通過(guò)
宿主語(yǔ)言或者 Excel 等應(yīng)用程序?qū)⒔Y(jié)果的格式轉(zhuǎn)換一下,才能使之成
為交叉表??瓷厦娴膱?zhí)行結(jié)果會(huì)發(fā)現(xiàn),此時(shí)輸出的已經(jīng)是側(cè)欄為縣
名、表頭為性別的交叉表了。在制作統(tǒng)計(jì)表時(shí),這個(gè)功能非常方便。
如果用一句話(huà)來(lái)形容這個(gè)技巧,可以這樣說(shuō):
新手用 WHERE 子句進(jìn)行條件分支,高手用 SELECT 子句進(jìn)行條件分
支。
在 UPDATE 語(yǔ)句里進(jìn)行條件分支
下面思考一下這樣一種需求:以某數(shù)值型的列的當(dāng)前值為判斷對(duì)象,
將其更新成別的值。這里的問(wèn)題是,此時(shí) UPDATE 操作的條件會(huì)有多
個(gè)分支。例如,我們通過(guò)下面這樣一張公司人事部的員工工資信息表
Salaries 來(lái)看一下這種情況。
假設(shè)現(xiàn)在需要根據(jù)以下條件對(duì)該表的數(shù)據(jù)進(jìn)行更新。
01. 對(duì)當(dāng)前工資為 30 萬(wàn)日元以上的員工,降薪 10%。
02. 對(duì)當(dāng)前工資為 25 萬(wàn)日元以上且不滿(mǎn) 28 萬(wàn)日元的員工,加薪
20%。
乍一看,分別執(zhí)行下面兩個(gè) UPDATE 操作好像就可以做到,但這樣的
結(jié)果卻是不正確的。
我們來(lái)分析一下不正確的原因。例如這里有一個(gè)員工,當(dāng)前工資是
30 萬(wàn)日元,按“條件 1”執(zhí)行 UPDATE 操作后,工資會(huì)被更新為 27 萬(wàn)
日元,但繼續(xù)按“條件 2”執(zhí)行 UPDATE 操作后,工資又會(huì)被更新為
32.4 萬(wàn)日元。
這樣的結(jié)果當(dāng)然并非人事部所愿。員工相田的工資必須被準(zhǔn)確地降為
27 萬(wàn)日元。問(wèn)題在于,第一次的 UPDATE 操作執(zhí)行后,“當(dāng)前工資”發(fā)
生了變化,如果還拿它當(dāng)作第二次 UPDATE 的判定條件,結(jié)果就會(huì)不
準(zhǔn)確。然而,即使將兩條 SQL 語(yǔ)句的執(zhí)行順序顛倒一下,當(dāng)前工資
為 27 萬(wàn)日元的員工,其工資的更新結(jié)果也會(huì)出現(xiàn)問(wèn)題。為了避免這
些問(wèn)題,準(zhǔn)確地表達(dá)出可惡的人事部長(zhǎng)的意圖,可以像下面這樣用
CASE 表達(dá)式來(lái)寫(xiě) SQL。
SQL 語(yǔ)句最后一行的 ELSE salary 非常重要,必須
寫(xiě)上。因?yàn)槿绻麤](méi)有它,條件 1 和條件 2 都不滿(mǎn)足的員工的工資就會(huì)
被更新成 NULL 。這一點(diǎn)與 CASE 表達(dá)式的設(shè)計(jì)有關(guān),在剛開(kāi)始介紹
CASE 表達(dá)式的時(shí)候我們就已經(jīng)了解到,如果 CASE 表達(dá)式里沒(méi)有明
確指定 ELSE 子句,執(zhí)行結(jié)果會(huì)被默認(rèn)地處理成 ELSE NULL ?,F(xiàn)在
大家明白筆者最開(kāi)始強(qiáng)調(diào)使用 CASE 表達(dá)式時(shí)要習(xí)慣性地寫(xiě)上 ELSE
子句的理由了吧?
這個(gè)技巧的應(yīng)用范圍很廣。例如,可以用它簡(jiǎn)單地完成主鍵值調(diào)換這
種繁重的工作。通常,當(dāng)我們想調(diào)換主鍵值 a 和 b 時(shí),需要將主鍵值
臨時(shí)轉(zhuǎn)換成某個(gè)中間值。使用這種方法時(shí)需要執(zhí)行 3 次 UPDATE 操
作,但是如果使用 CASE 表達(dá)式,1 次就可以做到。
顯而易見(jiàn),這條 SQL 語(yǔ)句按照“如果是 a 則更新為 b ,如果是 b 則更
新為 a ”這樣的條件分支進(jìn)行了 UPDATE 操作。
CASE 表達(dá)式的一大優(yōu)勢(shì)在于能夠判斷表達(dá)式。也就是說(shuō),在 CASE 表達(dá)式里,我們可以使用 BETWEEN 、LIKE和 < 、> 等便利的謂詞組合,以及能嵌套子查詢(xún)的 IN 和 EXISTS 謂詞。因此,CASE 表達(dá)式具有非常強(qiáng)大的表達(dá)能力。
如下所示,這里有一張資格培訓(xùn)學(xué)校的課程一覽表和一張管理每個(gè)月
所設(shè)課程的表。
我們要用這兩張表來(lái)生成下面這樣的交叉表,以便于一目了然地知道
每個(gè)月開(kāi)設(shè)的課程。
我們需要做的是,檢查表 OpenCourses 中的各月里有表 CourseMaster
中的哪些課程。這個(gè)匹配條件可以用 CASE 表達(dá)式來(lái)寫(xiě)。
使用IN
使用EXISTS
這樣的查詢(xún)沒(méi)有進(jìn)行聚合,因此也不需要排序,月份增加的時(shí)候僅修
改 SELECT 子句就可以了,擴(kuò)展性比較好。
無(wú)論使用 IN 還是 EXISTS ,得到的結(jié)果是一樣的,但從性能方面來(lái)
說(shuō), EXISTS 更好。通過(guò) EXISTS 進(jìn)行的子查詢(xún)能夠用到“month,
course_id ”這樣的主鍵索引,因此尤其是當(dāng)表 OpenCourses 里數(shù)據(jù)
比較多的時(shí)候更有優(yōu)勢(shì)。
在 CASE 表達(dá)式中使用聚合函數(shù)
接下來(lái)介紹一下稍微高級(jí)的用法。這個(gè)用法乍一看可能讓人覺(jué)得像是
語(yǔ)法錯(cuò)誤,實(shí)際上卻并非如此。我們來(lái)看一道例題,假設(shè)這里有一張
顯示了學(xué)生及其加入的社團(tuán)的一覽表。如表 StudentClub 所示,這張
表的主鍵是“學(xué)號(hào)、社團(tuán) ID”,存儲(chǔ)了學(xué)生和社團(tuán)之間多對(duì)多的關(guān)系
有的學(xué)生同時(shí)加入了多個(gè)社團(tuán)(如學(xué)號(hào)為 100、200 的學(xué)生),有的
學(xué)生只加入了某一個(gè)社團(tuán)(如學(xué)號(hào)為 300、400、500 的學(xué)生)。對(duì)于
加入了多個(gè)社團(tuán)的學(xué)生,我們通過(guò)將其“主社團(tuán)標(biāo)志”列設(shè)置為 Y 或
者 N 來(lái)表明哪一個(gè)社團(tuán)是他的主社團(tuán);對(duì)于只加入了一個(gè)社團(tuán)的學(xué)
生,我們將其“主社團(tuán)標(biāo)志”列設(shè)置為 N。
接下來(lái),我們按照下面的條件查詢(xún)這張表里的數(shù)據(jù)。
01. 獲取只加入了一個(gè)社團(tuán)的學(xué)生的社團(tuán) ID。
02. 獲取加入了多個(gè)社團(tuán)的學(xué)生的主社團(tuán) ID。
很容易想到的辦法是,針對(duì)兩個(gè)條件分別寫(xiě) SQL 語(yǔ)句來(lái)查詢(xún)。要想
知道學(xué)生“是否加入了多個(gè)社團(tuán)”,我們需要用 HAVING 子句對(duì)聚合結(jié)
果進(jìn)行判斷。
這樣做也能得到正確的結(jié)果,但需要寫(xiě)多條 SQL 語(yǔ)句。而如果使用
CASE 表達(dá)式,下面這一條 SQL 語(yǔ)句就可以了。
這條 SQL 語(yǔ)句在 CASE 表達(dá)式里使用了聚合函數(shù),又在聚合函數(shù)里使
用了 CASE 表達(dá)式。這種嵌套的寫(xiě)法讓人有點(diǎn)眼花繚亂,其主要目的
是用 CASE WHEN COUNT(*) = 1 …… ELSE ……. 這樣的 CASE 表達(dá)式
來(lái)表示“只加入了一個(gè)社團(tuán)還是加入了多個(gè)社團(tuán)”這樣的條件分支。我
們?cè)诔鯇W(xué) SQL 的時(shí)候,都學(xué)過(guò)對(duì)聚合結(jié)果進(jìn)行條件判斷時(shí)要用
HAVING 子句,但從這道例題可以看到,在 SELECT 語(yǔ)句里使用 CASE
表達(dá)式也可以完成同樣的工作,這種寫(xiě)法比較新穎。如果用一句話(huà)來(lái)
形容這個(gè)技巧,可以這樣說(shuō):
新手用 HAVING 子句進(jìn)行條件分支,高手用 SELECT 子句進(jìn)行條件分
支。
通過(guò)這道例題我們可以明白:CASE 表達(dá)式用在 SELECT 子句里時(shí),
既可以寫(xiě)在聚合函數(shù)內(nèi)部,也可以寫(xiě)在聚合函數(shù)外部。這種高度自由
的寫(xiě)法正是 CASE 表達(dá)式的魅力所在。
作為表達(dá)式,CASE 表達(dá)式在執(zhí)行時(shí)會(huì)被判定為一個(gè)固定值,因此它
可以寫(xiě)在聚合函數(shù)內(nèi)部;也正因?yàn)樗潜磉_(dá)式,所以還可以寫(xiě)在
SELECE 子句、GROUP BY 子句、WHERE 子句、ORDER BY 子句里。簡(jiǎn)
單點(diǎn)說(shuō),在能寫(xiě)列名和常量的地方,通常都可以寫(xiě) CASE 表達(dá)式。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“SQL中CASE表達(dá)式怎么用”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!