个人提交答案汇总,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() 函数区分
- rank() : 如果存在并列情况,会占用下一个名次的位置:1、1、3、4、4、6
- dense_rank() : 如果存在并列情况,不占用下一个名次的位置:1、1、2、3、3、4
- 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