牛客刷题——case when

a. case x1 when ‘01’ then’ 赋值 else 赋值 end
b. case when x1条件 then赋值 else 赋值 end

一、条件判断

(一)分不同情况计算

【例】46、查询各学生的年龄,按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

select s_birth,
(DATE_FORMAT(NOW(),'%Y')-DATE_FORMAT(s_birth,'%Y') - 
(case when DATE_FORMAT(NOW(),'%m%d')<DATE_FORMAT(s_birth,'%m%d') then 1 else 0 end)) as age
from student;

【例】SQL75 考试分数(四)
查询各个岗位分数升序排列之后的中位数位置的范围,并且按job升序排序

  • 思路:中位数涉及奇偶不同的情况,适合用case when:case when condition then else end
select job
        ,(case when count(score)%2=0 then ceiling(count(score)/2) else ceiling(count(score)/2)
        end)as start
        ,(case when count(score)%2=0 then ceiling(count(score)/2+1) else ceiling(count(score)/2)
        end) as end
from grade
group by job
order by job;

SQL41 各用户等级的不同得分表现占比

select level,score_grade,
round(count(score)/max(total_cnt),3) as ratio
from
(
    select ui.uid,level,score,
    (case when score between 90 and 100 then '优' when score between 75 and 89 then '良' when score between 60 and 74 then '中' else '差' end) as score_grade,
    count(score)over(partition by level) as total_cnt
    from exam_record er join user_info ui using(uid)
    where score is not null
)a
group by level,score_grade
order by level desc,ratio desc

(二)max(case var when…then…end) group by只选出符合条件的行

【例】17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

注:和groupby连用,取唯一值的情况——由于group不要取唯一值会默认取第一个,很多情况下第一个由于连接的原因是null,因此这里需要取最大值or求和,也就是需要在case when的外面套一个max或者sum。只有在符合情况下有value,其余情况都是0 or null,所以要用max

SELECT 
a.s_id,
max(CASE a.c_id WHEN '01' THEN a.s_score END ) 语文, -- 取max函数是因为,找到的第一个很可能是空值,需要借着找到最大的值才是答案
max(CASE a.c_id WHEN '02' THEN a.s_score END ) 数学, 
max(CASE a.c_id WHEN '03' THEN a.s_score END ) 英语, 
avg(a.s_score) 平均分,
b.s_name 
FROM Score a JOIN Student b 
ON a.s_id=b.s_id 
GROUP BY a.s_id 
ORDER BY 5 DESC		-- 从1开始计数

SQL81 牛客的课程订单分析(五)

  • 代码注意点:else null可以改成else 0
  • 思路:【窗口函数+casewhen】先用窗口函数构造出想要的变量,然后用case when条件筛选
select  -- select中的变量一定要有聚合性质
 user_id,
 max(case when rank_no=1 then a.date else null end) as first_buy_date,
 max(case when rank_no=2 then a.date else null end) as second_buy_date,
 cnt
from
    (select
     user_id,
     date,
     row_number() over(partition by user_id order by date) as rank_no,
     count(*) over(partition by user_id) as cnt
    from order_info
    where date >= '2025-10-16'
      and status = 'completed'
      and product_name in('C++','Java','Python')
    ) a
where rank_no<=2 and cnt>=2
group by user_id
order by user_id ;

(三)针对不同变量是在不同条件下生成的情况

SQL26 每个6/7级用户活跃情况
首先分别对考试表和做题表提取出每条考试记录的活跃年份、活跃月份、活跃日,然后做union。再把新表和用户信息表进行右连接,保留所有用户的信息。最后在连接的基础上分组计数。

select ui.uid,
count(distinct act_month) as act_month_total,
count(distinct case when act_year=2021 then act_day else null end) as act_days_2021,
count(distinct case when act_year=2021 and tag='exam' then act_day else null end) as act_days_2021_exam,
count(distinct case when act_year=2021 and tag='practice' then act_day else null end) as act_days_2021_question
from user_info ui left join 
(select uid,
year(start_time) as act_year,
date_format(start_time,'%Y%m') as act_month,
date_format(start_time,'%Y%m%d') as act_day,
'exam' as tag
from exam_record
union all 
select uid,
year(submit_time) as act_year,
date_format(submit_time,'%Y%m') as act_month,
date_format(submit_time,'%Y%m%d') as act_day,
'practice' as tag
from practice_record) exam_practice
using(uid)
where level in (6,7)
group by uid
order by act_month_total desc,act_days_2021 desc

二、计数用sum

(一)sum(case when in then 1 else 0 end) groupby

【例】SQL69 牛客每个人最近的登录日期(四)
查询每个日期登录新用户个数,并且查询结果按照日期升序排序

  • 思路1:【对case when in进行sum计数】首先可以得到每个用户最开始登录的日期,然后如果直接对这个表count会失去计数为0的日期。所以应该到原来的表里进行in的判断,是就放进计数,不是就不计数,也就是用到sum(case when 条件 then 1 else 0 end) groupby
  • 思路2:先窗口函数记录每个人的最早日期,再groupby后count计数
select date,
sum(case when (user_id,date) in 
(select user_id,min(date) from login group by user_id)  -- 求每个用户最早登录的日期
then 1 else 0 end) as new
from login
group by date
order by date

(二)sum(case when then 1 else 0 end) groupby

【例】18.查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率。及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90

select 
a.c_id,a.c_name,max(b.s_score) as max,min(b.s_score)as min,avg(b.s_score)as avg_score,
(100*sum(case when b.s_score>=60 then 1 else 0 end)/count(s_id))as 及格率,
(100*sum(case when b.s_score>=70 and b.s_score<80 then 1 else 0 end)/count(s_id))as 中等率,
(100*sum(case when b.s_score>=80 and b.s_score<90 then 1 else 0 end)/count(s_id))as 优良率,
(100*sum(case when b.s_score>=90 then 1 else 0 end)/count(s_id))as 优秀率
from course a left join score b 
on a.c_id = b.c_id 
GROUP BY a.c_id,a.c_name

等价于if(expression,a,b)

【例】SQL19 未完成试卷数大于1的有效用户

# 等价于sum(case when submit_time is null then 1 else null end)
select uid
        , sum(if(submit_time is null,1,null)) as incomplete_cnt
        , sum(if(submit_time is not null,1,null)) as complete_cnt
        , group_concat(distinct CONCAT(DATE_FORMAT(start_time, '%Y-%m-%d'),':',tag) separator ';') as detail
from exam_record er join examination_info ei using(exam_id)
where YEAR(start_time) = 2021 
group by uid
having incomplete_cnt>1
and incomplete_cnt<5
and complete_cnt >= 1
order by incomplete_cnt desc
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值