牛客网SQL刷题61-72

文章目录

    • 61、现在有一个需求,让你统计正常用户发送给正常用户邮件失败的概率
    • 62、牛客每天有很多人登录,请你统计一下牛客每个用户最近登录是哪一天。
    • 63、牛客每天有很多人登录,请你统计一下牛客每个用户最近登录是哪一天,用的是什么设备。
    • 64、牛客每天有很多人登录,请你统计一下牛客新登录用户的次日成功的留存率。
    • 65、请你写出一个sql语句查询每个日期登录新用户个数,并且查询结果按照日期升序排序。
    • 66、请你写出一个sql语句查询每个日期新用户的次日留存率,结果保留小数点后面3位数(3位之后的四舍五入),并且查询结果按照日期升序排序。
    • 67、请你写出一个sql语句查询刷题信息,包括: 用户的名字,以及截止到某天,累计总共通过了多少题,并且查询结果先按照日期升序排序,再按照姓名升序排序,有登录却没有刷题的哪一天的数据不需要输出。
    • 68、请你写一个sql语句查询各个岗位分数的平均数,并且按照分数降序排序,结果保留小数点后面3位(3位之后四舍五入)
    • 69、请你写一个sql语句查询用户分数大于其所在工作(job)分数的平均分的所有grade的属性,并且以id的升序排序。
    • 70、请你找出每个岗位分数排名前2的用户,得到的结果先按照language的name升序排序,再按照积分降序排序,最后按照grade的id升序排序。
    • 71、请你写一个sql语句查询各个岗位分数升序排列之后的中位数位置的范围,并且按job升序排序.
    • 72、请你写一个sql语句查询各个岗位分数的中位数位置上的所有grade信息,并且按id升序排序。

61、现在有一个需求,让你统计正常用户发送给正常用户邮件失败的概率

/*思路:按SQL运行顺序
1、建立一个除开黑名单用户(is_blacklist = 1)的子查询(相当于临时表),命名为表a.
注意:这里发送失败=未能成功接受,所以子查询的where条件语句中应同时包含对send_id和receive_id的处理
2、从表a中,按date分组
3、select部分:1)运用sum+case when表达式统计type为’no_completed’的数量作为发送失败的数量
4、在round函数中,计算每一天的失败率(当天失败数目/当天总的发送邮件数目),保留三位小数
*/

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

62、牛客每天有很多人登录,请你统计一下牛客每个用户最近登录是哪一天。

有一个登录(login)记录表,简况如下:
牛客网SQL刷题61-72_第1张图片
牛客网SQL刷题61-72_第2张图片
查询结果表明:
user_id为2的最近的登录日期在2020-10-13
user_id为3的最近的登录日期也是2020-10-13

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

63、牛客每天有很多人登录,请你统计一下牛客每个用户最近登录是哪一天,用的是什么设备。

开窗函数分组求最大时间,然后用子查询筛选。

select new.u_n,new.c_n,new.d from 
(
select login.user_id,user.`name` as u_n,client.`name` as c_n,login.date,
(max(login.date) over(PARTITION by login.user_id)) as d
from login,user,client
where login.user_id=user.id and login.client_id=client.id
) as new
where new.date=new.d
order by new.u_n asc

64、牛客每天有很多人登录,请你统计一下牛客新登录用户的次日成功的留存率。

方法1:
select round(count(b.user_id)/count(a.user_id),3)as p
from 
(select user_id,min(date)first_login from login group by user_id) as a
left join login as b on a.user_id=b.user_id 
and datediff(b.date,a.first_login)=1;

方法2:
select round(count(l2.date)/count(*),3) p
from (select user_id,min(date) first_date from login group by user_id) l1
left join login l2 on l1.user_id =l2.user_id 
and l2.date=date_add(l1.first_date,interval 1 day)

65、请你写出一个sql语句查询每个日期登录新用户个数,并且查询结果按照日期升序排序。

方法1- 先得到所有日期表select distinct date from login;
- 然后左连接新用户首次登陆的日期表(select user_id, min(date) first_date from login group by user_id);
- 归类统计日期出现的次数.

select a.date, count(b.user_id) new
from (select distinct date from login) a
left join 
(select user_id, min(date) first_date from login group by user_id) b 
on a.date=b.first_date 
group by a.date
order by a.date

方法2:使用窗口函数:
select date,sum(case when r=1 then 1 else 0 end)as new from(
select user_id,date,dense_rank()over(PARTITION by user_id order by date)as r
from login )as l
group by date
order by date

66、请你写出一个sql语句查询每个日期新用户的次日留存率,结果保留小数点后面3位数(3位之后的四舍五入),并且查询结果按照日期升序排序。

SELECT t0.d AS `date`, IFNULL(t3.cnt,0) AS p
FROM 
(	-- 为了补上没有新用户的日期
	SELECT DISTINCT(t.date) AS d FROM login t
) t0
LEFT JOIN
(
	SELECT t2.date, ROUND(COUNT(DISTINCT t2.user_id)/ COUNT(DISTINCT(t1.user_id)),3) AS cnt
	FROM (
	-- 得到新用户
		SELECT l1.DATE, l1.user_id
		FROM login AS l1
		WHERE l1.user_id NOT IN 
		(
			SELECT user_id FROM login WHERE DATE < l1.date)
		) t1,
-- 求新用户次日依然留存的用户
		(
		SELECT l1.date, l1.user_id 
		FROM login AS l1 
		WHERE l1.user_id IN
		(
			SELECT user_id	FROM login WHERE DATE= DATE_ADD(l1.DATE, INTERVAL 1 DAY))
		) t2
	WHERE t1.date=t2.date
	GROUP BY t2.date
) t3 
ON t0.d = t3.date
ORDER BY t0.d

67、请你写出一个sql语句查询刷题信息,包括: 用户的名字,以及截止到某天,累计总共通过了多少题,并且查询结果先按照日期升序排序,再按照姓名升序排序,有登录却没有刷题的哪一天的数据不需要输出。

两种方法:
1、使用窗口函数SUM,将日期作为“窗口”计算累加刷题数量:

SELECT name AS u_n,date,
SUM(number) OVER (PARTITION BY user_id ORDER BY date) AS ps_num
FROM passing_number AS p
INNER JOIN user
ON user.id=p.user_id
GROUP BY date,u_n
ORDER BY date,name

2、使用自联结:

SELECT name AS u_n,date,ps_num
FROM (
    SELECT p1.user_id,p1.date,SUM(p2.number)AS ps_num
    FROM  passing_number AS p1,passing_number AS p2
    WHERE p1.date>=p2.date
    AND p1.user_id=p2.user_id
    GROUP BY p1.date,p1.user_id
    ) AS p
INNER JOIN user
ON user.id=p.user_id
GROUP BY date,u_n
ORDER BY date,name

68、请你写一个sql语句查询各个岗位分数的平均数,并且按照分数降序排序,结果保留小数点后面3位(3位之后四舍五入)

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

69、请你写一个sql语句查询用户分数大于其所在工作(job)分数的平均分的所有grade的属性,并且以id的升序排序。

1、先求解平均分;
2、求解所有的id、job、score
3、左联结+筛选 (大于平均值)
4、升序排列

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

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


select g1.id,a.name,g1.score
from grade as g1
inner join language as a
on g1.language_id=a.id
where 
(select count(distinct g2.score)from grade as g2
 where g1.language_id=g2.language_id
 and g2.score>=g1.score
)<=2
order by a.name asc,g1.score desc,g1.id asc;

使用窗口函数:
select t1.id, t2.name, t1.score from
(select g.id, g.language_id, score, 
 DENSE_RANK() over(partition by language_id order by score desc) as r
from grade as g) t1
left join language as t2
on t1.language_id=t2.id
where t1.r <= 2
order by t2.name, t1.score desc, t1.id

71、请你写一个sql语句查询各个岗位分数升序排列之后的中位数位置的范围,并且按job升序排序.

如果是奇数个:那么 中位数的位置是(count(id)+1)/2
如果是偶数个:那么中位数的位置是floor((count(id)+1)/2) 和 ceil((count(id)+1)/2)

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

72、请你写一个sql语句查询各个岗位分数的中位数位置上的所有grade信息,并且按id升序排序。

找到每个用户每科成绩的排名;
找到中位数的取值范围;
将排名和中位数比较;
计算排名使用窗口函数dense_rank
使用case找到中位数的取值范围
将上面两步联合起来,增加排名和中位数比较的条件(or)

SELECT b.id,b.job,b.score,b.r
FROM (
    SELECT job,
    (CASE WHEN cnt%2=1 THEN (cnt+1)/2 ELSE (cnt/2) END) AS start,
    (CASE WHEN cnt%2=1 THEN (cnt+1)/2 ELSE (cnt/2+1) END) AS end
     FROM (
         SELECT job,COUNT(id) AS cnt
         FROM grade
         GROUP BY job)AS d) AS a
JOIN 
    (SELECT id,job,score,
    DENSE_RANK() OVER (PARTITION BY job ORDER BY score DESC) AS r
    FROM grade) AS b
ON a.job=b.job
WHERE b.r=a.start OR b.r=a.end
ORDER BY b.id

你可能感兴趣的:(SQL)