1.Case基本初識
case語句是mysql中的一個條件語句,可以在字段中使用case語句進行復(fù)雜的篩選以及構(gòu)造新的字段。下面通過兩個leetcode例子來詳細(xì)解讀case語句的功能:
1.1 Leetcode 627 (Easy) 交換工資
這道題目要求我們將sex字段的m和f交換,所以可以使用case語句進行條件判斷并賦給新的值。
# Write your MySQL query statement below
update salary set sex = (
case sex
when "m" then "f"
else "m"
end
);
1.2 Leetcode 626 (Medium) 換座位
這道題目要求我們換相鄰兩個同學(xué)的座位,所以可以交換id,使用case語句進行條件判斷之后并賦給新的值。
# Write your MySQL query statement below
select (case
when id%2 != 0 and id != (select count(id) as counts from seat) then id+1
when id%2 != 0 and id = counts then id
when id%2 =0 then id - 1
end
) as id, student from seat inner join (select count(id) as counts from seat) as seatcounts order by id;
注意此時的case后面沒有接任何字段,而是在when的判斷條件進行字段的控制篩選。
1.3 case語句的基本語法
我們將上述兩道leetcode題目進行以下case語法進行以下總結(jié):
# 對應(yīng)于627
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
# 對應(yīng)于626
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
2.Case語句進階實戰(zhàn)
2.1 熱身題目:列轉(zhuǎn)行操作
有一個成績表scores,想要實現(xiàn)每個學(xué)生的每門成績分別是多少?
scores表的結(jié)構(gòu)如下:
| id | name | course | score |
|---|---|---|---|
| 1 | 二狗 | math | 98 |
| 2 | 二狗 | chinese | 99 |
| 3 | 二狗 | english | 97 |
| 4 | 小白 | math | 78 |
| 5 | 小白 | chinese | 69 |
| 6 | 小白 | english | 84 |
想要按照以下的結(jié)構(gòu)輸出,如何編寫sql代碼呢?
| name | math | chinese | english |
|---|---|---|---|
| 二狗 | 98 | 99 | 97 |
| 小白 | 78 | 69 | 84 |
首先我們看到輸出表的結(jié)構(gòu)是以name進行分組,可以使用group by語句,寫出如下的格式:
select name from scores group by name;
其次需要思考如何把course的字段按照類別拆解成幾個字段呢,這時候就需要使用case語句進行條件控制判斷:
select name,
(case course when "math" then score else 0) as math,
(case course when "chinese" then score else 0) as chinese,
(case course when "english" then score else 0) as english
from scores;
通過上述語句的輸出如下:
| name | math | chinese | english |
|---|---|---|---|
| 二狗 | 98 | 0 | 0 |
| 二狗 | 0 | 99 | 0 |
| 二狗 | 0 | 0 | 97 |
| 小白 | 78 | 0 | 0 |
| 小白 | 0 | 69 | 0 |
| 小白 | 0 | 0 | 84 |
最后通過上述兩步驟整合,得到的代碼如下:
select name,
sum(case course when "math" then score else 0) as math,
sum(case course when "chinese" then score else 0) as chinese,
sum(case course when "english" then score else 0) as english
from scores group by name;
2.2 滴滴筆試題目(2021校招 DS數(shù)據(jù)分析試卷)
付費統(tǒng)計:
現(xiàn)有一個數(shù)據(jù)表t_user_payment,包含乘客的支付信息,其中有四個字段,id(string)訂單id,amount(int)支付金額,order_type(string)訂單類別,payment_chnl(string)支付渠道。
現(xiàn)在要依據(jù)不同的支付渠道統(tǒng)計以下三種訂單類型(kuaiche,shunfengche,zhuanche)的總支付金額,最終要包含四個字段payment_chnl,kuaiche_amt,shunfengche_amt,zhuanche_amt,按照payment_chnl正序排序。當(dāng)某種payment_chnl下無某種order_type訂單時,對應(yīng)的_amt取0。
樣例輸入描述:
| id | amount | order_type | payment_chnl |
|---|---|---|---|
| 1 | 10 | kuaiche | |
| 2 | 13 | kuaiche | alipay |
| 3 | 17 | kuaiche | other |
| 4 | 15 | shunfengche | alipay |
| 5 | 38 | shunfengche | |
| 6 | 20 | zhuanche | other |
| 7 | 9 | kuaiche | alipay |
| 8 | 25 | shunfengche |
樣例輸出描述:
| payment_chnl | kuaiche_amt | shunfengche_amt | zhuanche_amt |
|---|---|---|---|
| alipay | 21 | 15 | 0 |
| 10 | 63 | 0 | |
| other | 17 | 0 | 20 |
解答:顯然這是一個列轉(zhuǎn)行的問題,所以直接考慮使用case語句和group by:
select payment_chnl,
sum(case order_type when "kuaiche" then amount else 0) as kuaiche_amt,
sum(case order_type when "shunfengche" then amount else 0) as shunfengche_amt,
sum(case order_type when "zhuanche" then amount else 0) as zhuanche_amt,
from t_user_payment group by payment_chnl;
2.3 Leetcode 262 (Hard)行程和用戶
這道題目是出行領(lǐng)域的實際業(yè)務(wù)問題,比常規(guī)的題目要更復(fù)雜,因此需要讀者更加細(xì)心。
首先,需要利用自聯(lián)結(jié)篩選出沒有被禁止的用戶(司機和乘客)
select id, t.status, request_at
from trips as t
inner join users as u1 on u1.users_id = t.client_id and u1.banned = "No"
inner join users as u2 on u2.users_id = t.driver_id and u2.banned = "No";
其次,使用case語句對取消的訂單記為1,未取消的訂單記為0。
最后,計算出取消訂單率并篩選日期條件。
select request_at as Day,
round(sum(case when status != "completed" then 1 else 0 end)/count(status), 2) as "Cancellation Rate"
from trips as t
inner join users as u1 on u1.users_id = t.client_id and u1.banned = "No"
inner join users as u2 on u2.users_id = t.driver_id and u2.banned = "No"
where date(t.request_at) between "2013-10-1" and "2013-10-3"
group by t.request_at;
注意,自聯(lián)結(jié)的形式和表的別名。