【SQL】牛客sql题库答案汇总(61-80)

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

61、对于employees表中,输出first_name排名(按first_name升序排序)为奇数的first_name

select a.first_name from (
select first_name , emp_no, row_number() over(order by first_name) as cnt
from employees ) a
where a.cnt % 2 <> 0
order by a.emp_no

这道题就离谱,结果说不需要排序然后同样的答案,但是顺序不对就是ac不了

62、写一个sql查询,积分表里面出现三次以及三次以上的积分

select number
from grade
group by number 
having count(*) >= 3

63、输出通过的题目的排名,通过题目个数相同的,排名相同,此时按照id升序排列

select id
      ,number
      ,(
          select count(distinct number)
          from passing_number b
          where a.number < b.number
       ) + 1 as t_rank
from passing_number a
order by number desc , id

觉得应该有函数实现,所以看了评论区,有个小伙伴是这样写的,由此可见,学好窗口函数多么重要

SELECT
    id,number,
    dense_rank ( ) over ( ORDER BY number DESC ) `rank` 
FROM
    passing_number 
ORDER BY
    `rank`,
    id
  • rank() | dense_rank | row_number() 函数区分
  1. rank() : 如果存在并列情况,会占用下一个名次的位置:1、1、3、4、4、6
  2. dense_rank() : 如果存在并列情况,不占用下一个名次的位置:1、1、2、3、3、4
  3. row_number() : 忽视并列情况:1、2、3、4、5、6

64、请你找到每个人的任务情况,并且输出出来,没有任务的也要输出,而且输出结果按照person的id升序排序

select p.id
      ,p.name
      ,t.content
from person p left join task t on p.id = t.person_id
order by p.id

65、统计正常用户发送给正常用户邮件失败的概率:

select total.date as date
      ,round(sb.sb_p / total.total_p, 3) as p
from 
(select date, count(*) as total_p  from email
 where send_id in (select id from user where is_blacklist = '0') and
     receive_id in (select id from user where is_blacklist = '0')
 group by date
) total join
(select date, count(*) as sb_p from email where type = "no_completed"
 and send_id in (select id from user where is_blacklist = '0') and
     receive_id in (select id from user where is_blacklist = '0')
 group by date
) sb on total.date = sb.date

这道题我写的真的是繁琐又无脑,没有一点艺术性。。。
下面是牛客里其他小伙伴写的答案,感觉都很好,大家都是用case when解决的

select date,round(sum(case e.type when 'no_completed' then 1 else 0 end)*1.0/count(e.type),3) as p 
from email e
where send_id in (select id from user where is_blacklist = 0)
and receive_id in (select id from user where is_blacklist = 0)
group by date;

select date,
ROUND(AVG(CASE WHEN type = 'no_completed' THEN 1
     ELSE 0 END),3) AS p
from email
where send_id not in (select id from user where is_blacklist = 1)
and receive_id not in (select id from user where is_blacklist = 1)
group by date
//这个使用avg算概率,很巧妙

66、统计一下牛客每个用户最近登录是哪一天

select user_id
      ,date as d
from (
    select user_id
          ,date
          ,row_number() over(partition by user_id order by date desc) as num
    from login) a 
where a.num = 1 

这里想麻烦了···一直以为max不能用来取最近的日期,所以用了row_number···,下面是使用max的语句,超简单

select user_id,
       max(date) as d
from login
group by user_id
order by user_id;

67、查询每个用户最近一天登录的日子,用户的名字,以及用户用的设备的名字,并且查询结果按照user的name升序排序

我用的是row_number对每个用户的登录时间进行排序,取出第一条数据就是最近一次的登录

select a1.u_n, a1.c_n, a1.date from 
(select u.name as u_n
      ,c.name as c_n
      ,l.date as date
      ,row_number() over(partition by u.id order by date desc ) as num
from user u, client c, login l
where u.id = l.user_id and c.id = l.client_id) a1
where a1.num = 1
order by a1.u_n 

68、统计牛客新登录用户的次日成功的留存率

select round(b.next_user/count(distinct l.user_id), 3) as p
from login l,(
	select count(distinct l.user_id) as next_user from login l join (
		select user_id, min(date) as new_date from login group by user_id) a
		on l.user_id = a.user_id and l.date = date_add(a.new_date,interval 1 day)
)b

牛客里其他小伙伴的答案!这个写的很棒,简洁又优雅。

select 
round(count(distinct user_id)*1.0/(select count(distinct user_id) from login) ,3)
from login
where (user_id,date)
in (select user_id,DATE_ADD(min(date),INTERVAL 1 DAY) from login group by user_id);

69、统计牛客每个日期登录新用户个数

select distinct l.date 
      ,ifnull(b.id_cnt, 0) as new
from login l left join (
select a.date, count(a.user_id) as id_cnt from (
select user_id, min(date) date from login group by user_id) a group by a.date) b
on l.date = b.date

其他小伙伴的答案,这个是用rownumber,然后sum对人数求和,也很巧妙

select a.date,
sum(case when rank=1 then 1 else 0 end) new
from 
(select date, row_number() over(partition by user_id order by date) rank
from login) a
group by date;

70、统计牛客每个日期新用户的次日留存率

select new_tb.date as date
      ,ifnull(round(next_tb.next_user/new_tb.new_user, 3), 0) as p
from 
(select l.date, count(a.user_id) as new_user from (
    select distinct date from login) l left join (
    select min(date) as date, user_id from login group by user_id) a on l.date = a.date
group by l.date) new_tb
left join 
(select date_sub(date, interval 1 day) as date, count(user_id) as next_user from login where (user_id, date) in (
    select user_id, date_add(min(date), interval 1 day) from login group by user_id) 
group by date) next_tb
on new_tb.date = next_tb.date;

71、查询刷题信息,包括: 用户的名字,以及截止到某天,累计总共通过了多少题

这道题和之前的一道题很像,用sum() over(partition by)

select u.name as u_n, pn.date
      ,sum(pn.number) over(partition by pn.user_id order by pn.date) as ps_num
from passing_number pn join user u
on pn.user_id = u.id
order by pn.date, u.name

72、查询各个岗位分数的平均数,并且按照分数降序排序,结果保留小数点后面3位(3位之后四舍五入):

select job
      ,round(avg(score), 3) as avg
from grade group by job 
order by avg desc

73、查询用户分数大于其所在工作(job)分数的平均分的所有grade的属性,并且以id的升序排序

select grade.id, grade.job, grade.score from grade join (
    select job, avg(score) as avg from grade group by job
) a on grade.job = a.job where grade.score > a.avg
order by grade.id;

74、找出每个岗位分数排名前2名的用户,得到的结果先按照language的name升序排序,再按照积分降序排序,最后按照grade的id升序排序

select a.id, a.name, a.score
from (select grade.id, language.name, grade.score
          ,dense_rank() over(partition by language_id order by score desc) as num
     from grade join language on grade.language_id = language.id
     group by grade.id, language.name, grade.score) a
where a.num <= 2
order by a.name,a.score desc, a.id

75、查询各个岗位分数升序排列之后的中位数位置的范围,并且按job升序排序

我的代码真是一点艺术性都没有

select a.job
      ,case (a.cnt % 2) when '0' then round(a.cnt/2, 0)
                    when '1' then round((a.cnt+1) / 2, 0)
       end as start
      ,case (a.cnt % 2) when '0' then round(a.cnt/2 + 1, 0)
                    when '1' then round((a.cnt+1) /2, 0)
       end as end
from (
    select job, count(id) as cnt from grade group by job
) a
order by a.job

这是评论区小伙伴的代码,真真简洁,为什么我总是把问题复杂化

select job,
    floor((count(*)+1)/2) as start,
    floor(count(*)/2+1) as end
from grade  
group by job 
order by job;

76、查询各个岗位分数的中位数位置上的所有grade信息,并且按id升序排序

select b.* 
from (select job,
    floor((count(*)+1)/2) as start,
    floor(count(*)/2+1) as end
from grade  
group by job
order by job) a, (
select id, job, score, rank() over(partition by job order by score desc) as t_rank
from grade ) b
where a.job = b.job and (a.start = b.t_rank or a.end = b.t_rank)
order by id 

77、查询在2025-10-15以后状态为购买成功的C++课程或者Java课程或者Python的订单,并且按照order_info的id升序排序

select id, user_id, product_name, status, client_id , date
from order_info
where date > '2025-10-15' and product_name in ('C++', 'Java', 'Python')
and status = 'completed'
order by id

78、查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的user_id,并且按照user_id升序排序

select user_id from order_info 
where date > '2025-10-15' and product_name in ('C++', 'Java', 'Python')
and status = 'completed' 
group by user_id having count(id) >= 2
order by user_id

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

select * from order_info
where user_id in (
select user_id from order_info
where product_name in ('C++','Java','Python')
and status = 'completed'
and date > '2025-10-15'
 group by user_id
having count(user_id) > 1) 
and product_name in ('C++','Java','Python')
and status = 'completed'
and date > '2025-10-15'

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

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

评论区其他小伙伴的代码,写的很棒呀!

select user_id,min(date) first_buy_date,count(user_id) cnt
from order_info
where date > '2025-10-15'
and product_name in ('C++','Java','Python')
and status = 'completed'
group by user_id
having count(user_id) > 1
order by user_id

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