/*思路:按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;
有一个登录(login)记录表,简况如下:
查询结果表明:
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;
开窗函数分组求最大时间,然后用子查询筛选。
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
方法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)
方法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
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
两种方法:
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
select job,round(avg(score),3)as avg
from grade group by job order by avg desc;
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;
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
如果是奇数个:那么 中位数的位置是(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;
找到每个用户每科成绩的排名;
找到中位数的取值范围;
将排名和中位数比较;
计算排名使用窗口函数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