【SQL】牛客sql题库答案汇总(81-91)

个人提交答案汇总,part5
解答比较繁琐,有建议或好的想法欢迎评论区指出探讨=w=
1-20 答案链接在这里
21-40 答案链接在这里
41-60 答案链接在这里
61-80 答案链接在这里

81、写出一个sql语句查询在2025-10-15以后,如果有一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程,那么输出这个用户的user_id,以及满足前面条件的第一次购买成功的C++课程或Java课程或Python课程的日期first_buy_date,以及满足前面条件的第二次购买成功的C++课程或Java课程或Python课程的日期second_buy_date,以及购买成功的C++课程或Java课程或Python课程的次数cnt,并且输出结果按照user_id升序排序

select a.user_id
      ,min(case when b.user_rank = '1' then b.date end) as first_buy_date
      ,min(case when b.user_rank = '2' then b.date end) as second_buy_date
      ,a.cnt
from (
    select user_id, count(user_id) as cnt
    from order_info
    where product_name in ('C++', 'Python', 'Java') and status = 'completed'
    and date > '2025-10-15'
    group by user_id having count(user_id) >= 2
) a left join (
    select user_id, date
          ,row_number() over (partition by user_id order by date) as user_rank
    from order_info 
    where product_name in ('C++', 'Python', 'Java') and status = 'completed'
    and date > '2025-10-15'
    group by user_id, date
) b on a.user_id = b.user_id
group by a.user_id, a.cnt
order by a.user_id;

我的解答总是要繁琐点
本题我的思路是:a表查询购买2次以上的用户取出user_id和购买次数cnt,b表对所有用户的购买日期进行排序,两表进行关联取出第一次和第二次购买的日期进行输出

评论区其他精彩答案

select a.user_id,
min(date) as first_buy_date,
max(date) as second_buy_date,
a.cnt
from
(select user_id , date, row_number()over(partition by user_id order by date asc) r_number ,
count(id)over(partition by user_id)cnt
from order_info
where date > '2025-10-15'
and product_name in ('C++','Java','Python')
and status = 'completed')a
where a.r_number <= 2
and a.cnt >= 2
group by a.user_id , a.cnt
order by a.user_id asc;

82、写出一个sql语句查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的订单id,是否拼团以及客户端名字信息,最后一列如果是非拼团订单,则显示对应客户端名字,如果是拼团订单,则显示NULL,并且按照order_info的id升序排序

select b.id
      ,b.is_group_buy
      ,case b.is_group_buy when 'No' then c.name 
       else NULL end as client_name
from (
    select user_id
    from order_info
    where product_name in ('C++', 'Python', 'Java') and status = 'completed'
    and date > '2025-10-15'
    group by user_id having count(user_id) >= 2 
) a 
left join (
    select id, user_id, is_group_buy, client_id
    from order_info
    where product_name in ('C++', 'Python', 'Java') and status = 'completed'
    and date > '2025-10-15'
) b on a.user_id = b.user_id 
left join (
    select id, name from client
) c on b.client_id = c.id
order by b.id

评论区比较好的答案,我做了一点改动,原代码里的日期判定用的
datediff(date,“2025-10-15”)>0

select t2.id,t2.is_group_buy,t1.name as client_name
from client t1 right join
(
    select *,count(id) over(partition by user_id) as number
    from order_info
    where date > '2025-10-15'
      and status="completed"
      and product_name in ("C++","Java","Python")
) t2
on t1.id=t2.client_id
where t2.number >1
order by t2.id

83、写出一个sql语句查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的来源信息,第一列是显示的是客户端名字,如果是拼团订单则显示GroupBuy,第二列显示这个客户端(或者是拼团订单)有多少订单,最后结果按照第一列(source)升序排序

select case a.client_id
       when '0' then 'GroupBuy'
       else b.name end as source
      ,count(a.client_id) as cnt
from (
    select user_id, client_id, count(id) over(partition by user_id) as buy_cnt
    from order_info
    where product_name in ('C++', 'Java', 'Python')
    and date > '2025-10-15'
    and status = 'completed' 
) a left join client b on a.client_id = b.id
where a.buy_cnt >= 2
group by source
order by source

84、写出SQL语句查询在2025年内投递简历的岗位和数量,并且按数量降序排序

select job
      ,sum(num) as cnt
from resume_info
where left(date, 4) = '2025'
group by job
order by sum(num) desc

这里我使用的是left求年份,其实也可以用year

85、写出SQL语句查询在2025年内投递简历的每个岗位,每一个月内收到简历的数量,并且按先按月份降序排序,再按简历数目降序排序

select a.job
      ,case length(a.month) 
       when '1' then concat('2025-0',a.month) 
       else concat('2025-',a.month) end as mon
      ,a.cnt
from (
    select job
          ,month(date) as month
          ,sum(num) as cnt
    from resume_info where year(date) = '2025'
    group by job, month(date)
    order by month(date) desc, sum(num) desc
) a 

这道题输出偷巧了,用的concat拼接,真是太丢人了

  • DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据。
    MySQL DATE_FORMAT() 函数
    语法:DATE_FORMAT(date,format)
常用格式 对应描述
%Y –年,4 位
%m –月,数值(00-12
%M –月名
%k –小时(0-23)

评论区精彩代码

-- 按月统计数量并排序
select job,date_format(date,'%Y-%m') as mon,sum(num) as cnt
from resume_info
where date like '2025%'  -- 符合最左前缀匹配原则,也走索引
group by job,mon
order by mon desc,cnt desc;

86、写出SQL语句查询在2025年投递简历的每个岗位,每一个月内收到简历的数目,和对应的2026年的同一个月同岗位,收到简历的数目,最后的结果先按first_year_mon月份降序,再按job降序排序显示

select a.job
	  ,a.month as first_year_mon
	  ,a.cnt as first_year_cnt
	  ,b.month as second_year_mon
	  ,b.cnt as second_year_cnt
from (
	select job
		  ,date_format(date,'%Y-%m') as month
		  ,sum(num) as cnt
	from resume_info
	where year(date) = '2025'
	group by job, month
) a,
	(select job
		  ,date_format(date,'%Y-%m') as month
		  ,sum(num) as cnt
	from resume_info
	where year(date) = '2026'
	group by job, month
) b 
where a.job = b.job and right(a.month, 2) = right(b.month, 2)
order by first_year_mon desc, job desc;

87、写出一个SQL查询,如果一个学生知道了自己综合成绩以后,最差是排第几名? 结果按照grade升序排序

select grade
      ,(select sum(number) from class_grade b 
         where a.grade >= b.grade
        ) as t_rank
from class_grade a
order by grade;

【SQL】牛客sql题库答案汇总(81-91)_第1张图片

  • 常见ASCII码的大小规则:0-9 1)数字比字母要小。如 “7”<“F”;
    2)数字0比数字9要小,并按0到9顺序递增。如 “3”<“8” ;
    3)字母A比字母Z要小,并按A到Z顺序递增。如“A”<“Z” ;
    4)同个字母的大写字母比小写字母要小32。如“A”<“a” 。
  • 几个常见字母的ASCII码大小: “A”为65;“a”为97;“0”为 48

这个也有其他解法,用sum() over()

select grade
      ,sum(number) over(order by grade) as t_rank
from class_grade a
order by grade;

sum(…) over( ),对所有行求和
sum(…) over( order by … ), 连续求和
sum(…) over( partition by… ),同组内所行求和
sum(…) over( partition by… order by … ),同第1点中的排序求和原理,只是范围限制在组内
(sum() over() 参考文章:https://blog.csdn.net/imliuqun123/article/details/80063827)

88、老师想知道学生们综合成绩的中位数是什么档位,请你写SQL帮忙查询一下,如果只有1个中位数,输出1个,如果有2个中位数,按grade升序输出
没写出来···直接看评论区精彩代码

select grade from
    (select *, (tb1.ed - tb1.number) st, sum(number) over() tp 
     from    
         (select *, sum(number) over(order by grade) ed 
          from class_grade) tb1
    ) tb2
where tp/2 between st and ed;

最内层嵌套:
【SQL】牛客sql题库答案汇总(81-91)_第2张图片
内层嵌套:
【SQL】牛客sql题库答案汇总(81-91)_第3张图片
tp/2 between st and ed这个条件用的很绝,这个题解可以记下。

89、写一个SQL查找积分增加最高的用户的名字,以及他的总积分是多少(此题数据保证积分最高的用户有且只有1个)

select user.name
      ,b.num
from (
    select distinct a.user_id
          ,sum(a.grade_num) over(partition by a.user_id) as num
    from grade_info a join user b on a.user_id = b.id
    where a.type = 'add' order by num desc
    limit 1
) b, user
where user.id = b.user_id

90、写一个SQL查找积分增加最高的用户的id(可能有多个),名字,以及他的总积分是多少,查询结果按照id升序排序

select tb1.user_id
      ,user.name
      ,tb1.sum_num as grade_sum
from (
    select user_id
          ,sum(grade_num) as sum_num
    from grade_info
    group by user_id
) tb1,(
    select max(a.num) as sum_num
    from (
        select user_id
              ,sum(grade_num) as num
        from grade_info 
        where type = 'add'
        group by user_id
        ) a
) tb2, user
where tb1.sum_num = tb2.sum_num
and tb1.user_id = user.id

提交之后想到dense_rank也可以用来排序就试了试,ac,这个解法更简单些。

select a.user_id as id
      ,b.name as name
      ,a.num as grade_sum
from (
    select user_id
          ,sum(grade_num) as num
          ,dense_rank() over(order by sum(grade_num) desc ) as d_rank
    from grade_info
    where type = 'add'
    group by user_id
) a, user b
where a.user_id = b.id
and a.d_rank = '1'

91、写一个SQL查找积分最高的用户的id,名字,以及他的总积分是多少(可能有多个),查询结果按照id升序排序

select b.user_id
      ,user.name
      ,b.num
from (
    select a.*, dense_rank() over(order by a.num desc) as d_rank
    from (select ad.user_id
              ,case  
               when re.sum is NULL then ad.sum
               else (ad.sum - re.sum) end as num
        from (
            select user_id, sum(grade_num) as sum
            from grade_info where type = 'add' group by user_id
        ) ad left join (
            select user_id, sum(grade_num) as sum
            from grade_info where type = 'reduce' group by user_id
        ) re on ad.user_id = re.user_id
    ) a
) b, user
where b.user_id = user.id and b.d_rank = '1'

我是将add和reduce的分值单独查询之后加总,评论区发现了更简洁的写法,if的用法还是很重要的!

select id, name, grade_sum
from(select user_id, grade_sum, rank() over(order by grade_sum desc) ranking
from(select user_id, sum(if(type = 'add', grade_num, -grade_num)) grade_sum
from grade_info
group by user_id) n1) n2 
join user
on n2.user_id = user.id
where ranking = 1
order by id

okk!牛客的题终于刷完了!完结!

你可能感兴趣的:(数据库,mysql,数据库,sql)